feat: add puzzle clear template runtime
This commit is contained in:
@@ -23,6 +23,7 @@ module-wooden-fish = { workspace = true, features = ["spacetime-types"] }
|
||||
module-match3d = { workspace = true }
|
||||
module-npc = { workspace = true, features = ["spacetime-types"] }
|
||||
module-puzzle = { workspace = true, features = ["spacetime-types"] }
|
||||
module-puzzle-clear = { workspace = true, features = ["spacetime-types"] }
|
||||
module-progression = { workspace = true, features = ["spacetime-types"] }
|
||||
module-quest = { workspace = true, features = ["spacetime-types"] }
|
||||
module-runtime = { workspace = true, features = ["spacetime-types"] }
|
||||
|
||||
@@ -455,19 +455,42 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
.find(&AUTH_STORE_PROJECTION_META_ID.to_string())
|
||||
.map(|row| row.updated_at.to_micros_since_unix_epoch());
|
||||
|
||||
let snapshot = build_auth_store_snapshot_from_rows(users, identities, sessions)?;
|
||||
if let Some(updated_at_micros) = updated_at_micros {
|
||||
upsert_auth_store_snapshot_rows(ctx, &snapshot, updated_at_micros)?;
|
||||
}
|
||||
let snapshot_json = serde_json::to_string_pretty(&snapshot)
|
||||
.map_err(|error| format!("序列化认证快照失败:{error}"))?;
|
||||
|
||||
Ok(AuthStoreSnapshotRecord {
|
||||
snapshot_json: Some(snapshot_json),
|
||||
updated_at_micros,
|
||||
})
|
||||
}
|
||||
|
||||
fn build_auth_store_snapshot_from_rows(
|
||||
users: Vec<UserAccount>,
|
||||
identities: Vec<AuthIdentity>,
|
||||
sessions: Vec<RefreshSession>,
|
||||
) -> Result<PersistentAuthStoreSnapshot, String> {
|
||||
let valid_user_ids = users
|
||||
.iter()
|
||||
.map(|user| user.user_id.clone())
|
||||
.collect::<std::collections::HashSet<_>>();
|
||||
let mut phone_identity_by_user_id = std::collections::HashMap::new();
|
||||
let mut phone_to_user_id = std::collections::HashMap::new();
|
||||
let mut wechat_identity_by_provider_uid = std::collections::HashMap::new();
|
||||
let mut user_id_by_provider_union_id = std::collections::HashMap::new();
|
||||
|
||||
for identity in identities {
|
||||
if !valid_user_ids.contains(&identity.user_id) {
|
||||
continue;
|
||||
}
|
||||
match identity.provider.as_str() {
|
||||
"phone" => {
|
||||
let phone_number = identity
|
||||
.phone_e164
|
||||
.clone()
|
||||
.unwrap_or_else(|| identity.provider_uid.clone());
|
||||
phone_to_user_id.insert(phone_number.clone(), identity.user_id.clone());
|
||||
phone_identity_by_user_id.insert(identity.user_id, phone_number);
|
||||
}
|
||||
"wechat" => {
|
||||
@@ -490,6 +513,7 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
}
|
||||
|
||||
let mut next_user_id = 1_u64;
|
||||
let mut phone_to_user_id = std::collections::HashMap::new();
|
||||
let mut users_by_username = std::collections::HashMap::new();
|
||||
for user in users {
|
||||
if let Some(numeric_id) = user
|
||||
@@ -499,6 +523,13 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
{
|
||||
next_user_id = next_user_id.max(numeric_id.saturating_add(1));
|
||||
}
|
||||
let phone_number = user
|
||||
.phone_number_e164
|
||||
.clone()
|
||||
.or_else(|| phone_identity_by_user_id.remove(&user.user_id));
|
||||
if let Some(phone_number) = phone_number.clone() {
|
||||
phone_to_user_id.insert(phone_number, user.user_id.clone());
|
||||
}
|
||||
let auth_user = AuthUserSnapshot {
|
||||
id: user.user_id.clone(),
|
||||
public_user_code: user.public_user_code,
|
||||
@@ -519,9 +550,7 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
user: auth_user,
|
||||
password_hash: user.password_hash,
|
||||
password_login_enabled: user.password_login_enabled,
|
||||
phone_number: user
|
||||
.phone_number_e164
|
||||
.or_else(|| phone_identity_by_user_id.remove(&user.user_id)),
|
||||
phone_number,
|
||||
},
|
||||
);
|
||||
}
|
||||
@@ -554,7 +583,7 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
);
|
||||
}
|
||||
|
||||
let snapshot = PersistentAuthStoreSnapshot {
|
||||
Ok(PersistentAuthStoreSnapshot {
|
||||
next_user_id,
|
||||
users_by_username,
|
||||
phone_to_user_id,
|
||||
@@ -562,16 +591,6 @@ fn export_auth_store_snapshot_from_tables_tx(
|
||||
session_id_by_refresh_token_hash,
|
||||
wechat_identity_by_provider_uid,
|
||||
user_id_by_provider_union_id,
|
||||
};
|
||||
if let Some(updated_at_micros) = updated_at_micros {
|
||||
upsert_auth_store_snapshot_rows(ctx, &snapshot, updated_at_micros)?;
|
||||
}
|
||||
let snapshot_json = serde_json::to_string_pretty(&snapshot)
|
||||
.map_err(|error| format!("序列化认证快照失败:{error}"))?;
|
||||
|
||||
Ok(AuthStoreSnapshotRecord {
|
||||
snapshot_json: Some(snapshot_json),
|
||||
updated_at_micros,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -710,4 +729,47 @@ mod tests {
|
||||
auth_store_snapshot_row_ids(&after)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn auth_export_ignores_phone_identity_without_user_account() {
|
||||
let live_user = UserAccount {
|
||||
user_id: "user_live".to_string(),
|
||||
public_user_code: "SY-00000001".to_string(),
|
||||
username: "phone_live".to_string(),
|
||||
display_name: "测试玩家".to_string(),
|
||||
avatar_url: None,
|
||||
phone_number_masked: Some("138****8000".to_string()),
|
||||
phone_number_e164: Some("+8613800008000".to_string()),
|
||||
login_method: "phone".to_string(),
|
||||
binding_status: "active".to_string(),
|
||||
wechat_bound: false,
|
||||
password_hash: "hash-live".to_string(),
|
||||
password_login_enabled: true,
|
||||
token_version: 1,
|
||||
user_tags: Some(vec![]),
|
||||
};
|
||||
let orphan_identity = AuthIdentity {
|
||||
identity_id: "authi_phone_orphan".to_string(),
|
||||
user_id: "user_deleted".to_string(),
|
||||
provider: "phone".to_string(),
|
||||
provider_uid: "+8613900009999".to_string(),
|
||||
provider_union_id: None,
|
||||
phone_e164: Some("+8613900009999".to_string()),
|
||||
display_name: None,
|
||||
avatar_url: None,
|
||||
};
|
||||
|
||||
let snapshot =
|
||||
build_auth_store_snapshot_from_rows(vec![live_user], vec![orphan_identity], vec![])
|
||||
.expect("auth rows should export");
|
||||
|
||||
assert_eq!(
|
||||
snapshot.phone_to_user_id,
|
||||
std::collections::HashMap::from([(
|
||||
"+8613800008000".to_string(),
|
||||
"user_live".to_string()
|
||||
)])
|
||||
);
|
||||
assert!(!snapshot.phone_to_user_id.contains_key("+8613900009999"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5521,6 +5521,7 @@ mod tests {
|
||||
deleted_at: None,
|
||||
created_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
updated_at: Timestamp::from_micros_since_unix_epoch(1),
|
||||
visible: true,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ pub use module_inventory::*;
|
||||
pub use module_jump_hop::*;
|
||||
pub use module_npc::*;
|
||||
pub use module_progression::*;
|
||||
pub use module_puzzle_clear::*;
|
||||
pub use module_quest::*;
|
||||
pub use module_runtime::*;
|
||||
pub use module_runtime_item::*;
|
||||
@@ -36,6 +37,7 @@ mod match3d;
|
||||
mod migration;
|
||||
mod public_work;
|
||||
mod puzzle;
|
||||
mod puzzle_clear;
|
||||
mod runtime;
|
||||
mod square_hole;
|
||||
mod visual_novel;
|
||||
@@ -54,6 +56,7 @@ pub use jump_hop::*;
|
||||
pub use match3d::*;
|
||||
pub use migration::*;
|
||||
pub use public_work::*;
|
||||
pub use puzzle_clear::*;
|
||||
pub use runtime::*;
|
||||
pub use square_hole::*;
|
||||
pub use visual_novel::*;
|
||||
|
||||
@@ -22,6 +22,10 @@ use crate::puzzle::{
|
||||
puzzle_agent_message, puzzle_agent_session, puzzle_event, puzzle_leaderboard_entry,
|
||||
puzzle_runtime_run, puzzle_work_profile,
|
||||
};
|
||||
use crate::puzzle_clear::tables::{
|
||||
puzzle_clear_agent_session, puzzle_clear_event, puzzle_clear_runtime_run,
|
||||
puzzle_clear_work_profile,
|
||||
};
|
||||
use crate::square_hole::tables::{
|
||||
square_hole_agent_message, square_hole_agent_session, square_hole_runtime_run,
|
||||
square_hole_work_profile,
|
||||
@@ -229,6 +233,10 @@ macro_rules! migration_tables {
|
||||
puzzle_event,
|
||||
puzzle_runtime_run,
|
||||
puzzle_leaderboard_entry,
|
||||
puzzle_clear_agent_session,
|
||||
puzzle_clear_work_profile,
|
||||
puzzle_clear_runtime_run,
|
||||
puzzle_clear_event,
|
||||
bark_battle_draft_config,
|
||||
bark_battle_published_config,
|
||||
bark_battle_runtime_run,
|
||||
@@ -1313,6 +1321,7 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
|
||||
if matches!(
|
||||
table_name,
|
||||
"jump_hop_work_profile"
|
||||
| "puzzle_clear_work_profile"
|
||||
| "square_hole_work_profile"
|
||||
| "visual_novel_work_profile"
|
||||
| "bark_battle_published_config"
|
||||
@@ -1322,6 +1331,12 @@ fn normalize_migration_row(table_name: &str, value: &serde_json::Value) -> serde
|
||||
object
|
||||
.entry("visible".to_string())
|
||||
.or_insert_with(|| serde_json::Value::Bool(true));
|
||||
if table_name == "puzzle_clear_work_profile" {
|
||||
// 中文注释:拼消消底图提示词字段晚于作品表加入,旧迁移包按空提示词兼容。
|
||||
object
|
||||
.entry("board_background_prompt".to_string())
|
||||
.or_insert(serde_json::Value::Null);
|
||||
}
|
||||
}
|
||||
}
|
||||
if table_name == "match_3_d_work_profile" || table_name == "match3d_work_profile" {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use crate::puzzle::{PuzzleGalleryCardViewRow, puzzle_gallery_card_view, puzzle_gallery_view};
|
||||
use crate::puzzle_clear::{puzzle_clear_gallery_card_view, puzzle_clear_gallery_view};
|
||||
use crate::*;
|
||||
use module_custom_world::{CustomWorldGalleryEntrySnapshot, CustomWorldProfileSnapshot};
|
||||
use module_puzzle::PuzzleWorkProfile;
|
||||
@@ -17,6 +18,11 @@ pub fn public_work_gallery_entry(ctx: &AnonymousViewContext) -> Vec<PublicWorkGa
|
||||
.into_iter()
|
||||
.map(map_puzzle_gallery_entry),
|
||||
);
|
||||
entries.extend(
|
||||
puzzle_clear_gallery_card_view(ctx)
|
||||
.into_iter()
|
||||
.map(map_puzzle_clear_gallery_entry),
|
||||
);
|
||||
entries.extend(
|
||||
custom_world_public_gallery_snapshots(ctx)
|
||||
.into_iter()
|
||||
@@ -74,6 +80,11 @@ pub fn public_work_detail_entry(ctx: &AnonymousViewContext) -> Vec<PublicWorkDet
|
||||
.into_iter()
|
||||
.map(map_puzzle_detail_entry),
|
||||
);
|
||||
entries.extend(
|
||||
puzzle_clear_gallery_view(ctx)
|
||||
.into_iter()
|
||||
.map(map_puzzle_clear_detail_entry),
|
||||
);
|
||||
entries.extend(
|
||||
custom_world_public_profile_snapshots(ctx)
|
||||
.into_iter()
|
||||
@@ -273,6 +284,65 @@ fn map_puzzle_detail_entry(row: PuzzleWorkProfile) -> PublicWorkDetailEntry {
|
||||
gallery_to_detail(entry, detail_payload_json)
|
||||
}
|
||||
|
||||
fn map_puzzle_clear_gallery_entry(row: PuzzleClearGalleryCardViewRow) -> PublicWorkGalleryEntry {
|
||||
let sort_time_micros = row.published_at_micros.unwrap_or(row.updated_at_micros);
|
||||
|
||||
PublicWorkGalleryEntry {
|
||||
source_type: "puzzle-clear".to_string(),
|
||||
work_id: row.work_id,
|
||||
profile_id: row.profile_id,
|
||||
source_session_id: None,
|
||||
public_work_code: row.public_work_code,
|
||||
owner_user_id: row.owner_user_id,
|
||||
author_display_name: row.author_display_name,
|
||||
world_name: row.work_title,
|
||||
subtitle: "拼消消".to_string(),
|
||||
summary_text: row.work_description,
|
||||
cover_image_src: row.cover_image_src,
|
||||
cover_asset_id: None,
|
||||
theme_tags: fallback_tags(vec![row.theme_prompt], &["拼消消"]),
|
||||
play_count: row.play_count,
|
||||
remix_count: 0,
|
||||
like_count: 0,
|
||||
published_at_micros: row.published_at_micros,
|
||||
updated_at_micros: row.updated_at_micros,
|
||||
sort_time_micros,
|
||||
}
|
||||
}
|
||||
|
||||
fn map_puzzle_clear_detail_entry(row: PuzzleClearGalleryViewRow) -> PublicWorkDetailEntry {
|
||||
let entry = PublicWorkGalleryEntry {
|
||||
source_type: "puzzle-clear".to_string(),
|
||||
work_id: row.work_id,
|
||||
profile_id: row.profile_id.clone(),
|
||||
source_session_id: empty_string_to_option(row.source_session_id),
|
||||
public_work_code: build_prefixed_public_work_code("PC", &row.profile_id),
|
||||
owner_user_id: row.owner_user_id,
|
||||
author_display_name: row.author_display_name,
|
||||
world_name: row.work_title,
|
||||
subtitle: "拼消消".to_string(),
|
||||
summary_text: row.work_description,
|
||||
cover_image_src: row.cover_image_src,
|
||||
cover_asset_id: None,
|
||||
theme_tags: fallback_tags(vec![row.theme_prompt.clone()], &["拼消消"]),
|
||||
play_count: row.play_count,
|
||||
remix_count: 0,
|
||||
like_count: 0,
|
||||
published_at_micros: row.published_at_micros,
|
||||
updated_at_micros: row.updated_at_micros,
|
||||
sort_time_micros: row.published_at_micros.unwrap_or(row.updated_at_micros),
|
||||
};
|
||||
let detail_payload_json = json_string(json!({
|
||||
"sourceType": "puzzle-clear",
|
||||
"themePrompt": row.theme_prompt,
|
||||
"patternGroupCount": row.pattern_groups.len(),
|
||||
"cardAssetCount": row.card_assets.len(),
|
||||
"generationStatus": row.generation_status,
|
||||
"hasBoardBackground": row.board_background_asset.is_some(),
|
||||
}));
|
||||
gallery_to_detail(entry, detail_payload_json)
|
||||
}
|
||||
|
||||
fn map_custom_world_gallery_entry(row: CustomWorldGalleryEntrySnapshot) -> PublicWorkGalleryEntry {
|
||||
PublicWorkGalleryEntry {
|
||||
source_type: "custom-world".to_string(),
|
||||
|
||||
1647
server-rs/crates/spacetime-module/src/puzzle_clear.rs
Normal file
1647
server-rs/crates/spacetime-module/src/puzzle_clear.rs
Normal file
File diff suppressed because it is too large
Load Diff
88
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs
Normal file
88
server-rs/crates/spacetime-module/src/puzzle_clear/tables.rs
Normal file
@@ -0,0 +1,88 @@
|
||||
use crate::*;
|
||||
|
||||
const WORK_VISIBLE_DEFAULT: bool = true;
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = puzzle_clear_agent_session,
|
||||
index(accessor = by_puzzle_clear_agent_session_owner_user_id, btree(columns = [owner_user_id]))
|
||||
)]
|
||||
pub struct PuzzleClearAgentSessionRow {
|
||||
#[primary_key]
|
||||
pub(crate) session_id: String,
|
||||
pub(crate) owner_user_id: String,
|
||||
pub(crate) status: String,
|
||||
pub(crate) draft_json: String,
|
||||
pub(crate) published_profile_id: String,
|
||||
pub(crate) created_at: Timestamp,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = puzzle_clear_work_profile,
|
||||
index(accessor = by_puzzle_clear_work_owner_user_id, btree(columns = [owner_user_id])),
|
||||
index(accessor = by_puzzle_clear_work_publication_status, btree(columns = [publication_status]))
|
||||
)]
|
||||
pub struct PuzzleClearWorkProfileRow {
|
||||
#[primary_key]
|
||||
pub(crate) profile_id: String,
|
||||
pub(crate) work_id: String,
|
||||
pub(crate) owner_user_id: String,
|
||||
pub(crate) source_session_id: String,
|
||||
pub(crate) author_display_name: String,
|
||||
pub(crate) work_title: String,
|
||||
pub(crate) work_description: String,
|
||||
pub(crate) theme_prompt: String,
|
||||
pub(crate) generate_board_background: bool,
|
||||
pub(crate) board_background_asset_json: String,
|
||||
#[default(None::<String>)]
|
||||
pub(crate) board_background_prompt: Option<String>,
|
||||
pub(crate) card_back_image_src: String,
|
||||
pub(crate) atlas_asset_json: String,
|
||||
pub(crate) pattern_groups_json: String,
|
||||
pub(crate) card_assets_json: String,
|
||||
pub(crate) cover_image_src: String,
|
||||
pub(crate) generation_status: String,
|
||||
pub(crate) publication_status: String,
|
||||
pub(crate) play_count: u32,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
pub(crate) published_at: Option<Timestamp>,
|
||||
// 中文注释:后台可见性开关,隐藏后不进入公开列表。
|
||||
#[default(WORK_VISIBLE_DEFAULT)]
|
||||
pub(crate) visible: bool,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = puzzle_clear_runtime_run,
|
||||
index(accessor = by_puzzle_clear_run_owner_user_id, btree(columns = [owner_user_id])),
|
||||
index(accessor = by_puzzle_clear_run_profile_id, btree(columns = [profile_id]))
|
||||
)]
|
||||
pub struct PuzzleClearRuntimeRunRow {
|
||||
#[primary_key]
|
||||
pub(crate) run_id: String,
|
||||
pub(crate) owner_user_id: String,
|
||||
pub(crate) profile_id: String,
|
||||
pub(crate) status: String,
|
||||
pub(crate) level_index: u32,
|
||||
pub(crate) clears_done: u32,
|
||||
pub(crate) snapshot_json: String,
|
||||
pub(crate) started_at_ms: i64,
|
||||
pub(crate) finished_at_ms: i64,
|
||||
pub(crate) created_at: Timestamp,
|
||||
pub(crate) updated_at: Timestamp,
|
||||
}
|
||||
|
||||
#[spacetimedb::table(
|
||||
accessor = puzzle_clear_event,
|
||||
index(accessor = by_puzzle_clear_event_profile_id, btree(columns = [profile_id])),
|
||||
index(accessor = by_puzzle_clear_event_run_id, btree(columns = [run_id]))
|
||||
)]
|
||||
pub struct PuzzleClearEventRow {
|
||||
#[primary_key]
|
||||
pub(crate) event_id: String,
|
||||
pub(crate) owner_user_id: String,
|
||||
pub(crate) profile_id: String,
|
||||
pub(crate) run_id: String,
|
||||
pub(crate) event_type: String,
|
||||
pub(crate) result: String,
|
||||
pub(crate) occurred_at: Timestamp,
|
||||
}
|
||||
304
server-rs/crates/spacetime-module/src/puzzle_clear/types.rs
Normal file
304
server-rs/crates/spacetime-module/src/puzzle_clear/types.rs
Normal file
@@ -0,0 +1,304 @@
|
||||
use crate::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub const PUZZLE_CLEAR_TEMPLATE_ID: &str = "puzzle-clear";
|
||||
pub const PUZZLE_CLEAR_TEMPLATE_NAME: &str = "拼消消";
|
||||
pub const PUZZLE_CLEAR_PUBLICATION_DRAFT: &str = "draft";
|
||||
pub const PUZZLE_CLEAR_PUBLICATION_PUBLISHED: &str = "published";
|
||||
pub const PUZZLE_CLEAR_GENERATION_DRAFT: &str = "draft";
|
||||
pub const PUZZLE_CLEAR_GENERATION_READY: &str = "ready";
|
||||
pub const PUZZLE_CLEAR_GENERATION_FAILED: &str = "failed";
|
||||
pub const PUZZLE_CLEAR_CARD_BACK_IMAGE_SRC: &str = "/creation-type-references/puzzle.webp";
|
||||
pub const PUZZLE_CLEAR_EVENT_RUN_STARTED: &str = "run-started";
|
||||
pub const PUZZLE_CLEAR_EVENT_SWAP: &str = "swap";
|
||||
pub const PUZZLE_CLEAR_EVENT_RETRY_LEVEL: &str = "retry-level";
|
||||
pub const PUZZLE_CLEAR_EVENT_NEXT_LEVEL: &str = "next-level";
|
||||
pub const PUZZLE_CLEAR_EVENT_TIME_UP: &str = "time-up";
|
||||
pub const PUZZLE_CLEAR_EVENT_LEVEL_COMPLETED: &str = "level-completed";
|
||||
pub const PUZZLE_CLEAR_EVENT_RUN_FINISHED: &str = "run-finished";
|
||||
pub const PUZZLE_CLEAR_EVENT_LEVEL_FAILED: &str = "level-failed";
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearAgentSessionCreateInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_prompt: String,
|
||||
pub generate_board_background: bool,
|
||||
pub board_background_asset_json: Option<String>,
|
||||
pub board_background_prompt: String,
|
||||
pub created_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearAgentSessionGetInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearDraftCompileInput {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
pub author_display_name: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_prompt: String,
|
||||
pub generate_board_background: bool,
|
||||
pub board_background_asset_json: Option<String>,
|
||||
pub board_background_prompt: String,
|
||||
pub atlas_asset_json: Option<String>,
|
||||
pub pattern_groups_json: Option<String>,
|
||||
pub card_assets_json: Option<String>,
|
||||
pub generation_status: Option<String>,
|
||||
pub compiled_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorkUpdateInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_prompt: String,
|
||||
pub generate_board_background: bool,
|
||||
pub board_background_asset_json: Option<String>,
|
||||
pub board_background_prompt: String,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorkPublishInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub published_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorksListInput {
|
||||
pub owner_user_id: String,
|
||||
pub published_only: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorkGetInput {
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunStartInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub profile_id: String,
|
||||
pub client_event_id: String,
|
||||
pub started_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunGetInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunSwapInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub from_row: u32,
|
||||
pub from_col: u32,
|
||||
pub to_row: u32,
|
||||
pub to_col: u32,
|
||||
pub client_action_id: String,
|
||||
pub swapped_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunRetryLevelInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub client_action_id: String,
|
||||
pub restarted_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunNextLevelInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub client_action_id: String,
|
||||
pub started_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunTimeUpInput {
|
||||
pub run_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub client_action_id: String,
|
||||
pub occurred_at_ms: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct PuzzleClearAgentSessionProcedureResult {
|
||||
pub ok: bool,
|
||||
pub session: Option<PuzzleClearAgentSessionSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorkProcedureResult {
|
||||
pub ok: bool,
|
||||
pub work: Option<PuzzleClearWorkSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct PuzzleClearWorksProcedureResult {
|
||||
pub ok: bool,
|
||||
pub items: Vec<PuzzleClearWorkSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, SpacetimeType)]
|
||||
pub struct PuzzleClearRunProcedureResult {
|
||||
pub ok: bool,
|
||||
pub run: Option<PuzzleClearRuntimeSnapshot>,
|
||||
pub error_message: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearImageAssetSnapshot {
|
||||
pub asset_id: String,
|
||||
pub image_src: String,
|
||||
pub image_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub generation_provider: String,
|
||||
pub prompt: String,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearPatternGroupSnapshot {
|
||||
pub group_id: String,
|
||||
pub shape: String,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub atlas_x: u32,
|
||||
pub atlas_y: u32,
|
||||
pub atlas_width: u32,
|
||||
pub atlas_height: u32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearCardAssetSnapshot {
|
||||
pub card_id: String,
|
||||
pub group_id: String,
|
||||
pub shape: String,
|
||||
pub orientation: String,
|
||||
pub part_x: u32,
|
||||
pub part_y: u32,
|
||||
pub image_src: String,
|
||||
pub image_object_key: String,
|
||||
pub asset_object_id: String,
|
||||
pub source_atlas_cell: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearDraftSnapshot {
|
||||
pub template_id: String,
|
||||
pub template_name: String,
|
||||
pub profile_id: Option<String>,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_prompt: String,
|
||||
pub generate_board_background: bool,
|
||||
pub board_background_asset: Option<PuzzleClearImageAssetSnapshot>,
|
||||
#[serde(default)]
|
||||
pub board_background_prompt: String,
|
||||
pub card_back_image_src: Option<String>,
|
||||
pub atlas_asset: Option<PuzzleClearImageAssetSnapshot>,
|
||||
pub pattern_groups: Vec<PuzzleClearPatternGroupSnapshot>,
|
||||
pub card_assets: Vec<PuzzleClearCardAssetSnapshot>,
|
||||
pub generation_status: String,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearAgentSessionSnapshot {
|
||||
pub session_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
pub draft: Option<PuzzleClearDraftSnapshot>,
|
||||
pub published_profile_id: Option<String>,
|
||||
pub created_at_micros: i64,
|
||||
pub updated_at_micros: i64,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearWorkSnapshot {
|
||||
pub work_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub source_session_id: String,
|
||||
pub author_display_name: String,
|
||||
pub work_title: String,
|
||||
pub work_description: String,
|
||||
pub theme_prompt: String,
|
||||
pub generate_board_background: bool,
|
||||
pub board_background_asset: Option<PuzzleClearImageAssetSnapshot>,
|
||||
#[serde(default)]
|
||||
pub board_background_prompt: String,
|
||||
pub card_back_image_src: Option<String>,
|
||||
pub atlas_asset: PuzzleClearImageAssetSnapshot,
|
||||
pub pattern_groups: Vec<PuzzleClearPatternGroupSnapshot>,
|
||||
pub card_assets: Vec<PuzzleClearCardAssetSnapshot>,
|
||||
pub cover_image_src: Option<String>,
|
||||
pub publication_status: String,
|
||||
pub publish_ready: bool,
|
||||
pub play_count: u32,
|
||||
pub generation_status: String,
|
||||
pub updated_at_micros: i64,
|
||||
pub published_at_micros: Option<i64>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearBoardCellSnapshot {
|
||||
pub row: u32,
|
||||
pub col: u32,
|
||||
pub card: Option<PuzzleClearCardAssetSnapshot>,
|
||||
pub locked_group_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearBoardSnapshot {
|
||||
pub rows: u32,
|
||||
pub cols: u32,
|
||||
pub cells: Vec<PuzzleClearBoardCellSnapshot>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, SpacetimeType)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct PuzzleClearRuntimeSnapshot {
|
||||
pub run_id: String,
|
||||
pub profile_id: String,
|
||||
pub owner_user_id: String,
|
||||
pub status: String,
|
||||
pub level_index: u32,
|
||||
pub clears_done: u32,
|
||||
pub target_clears: u32,
|
||||
pub level_duration_seconds: u32,
|
||||
pub level_started_at_ms: u64,
|
||||
pub board: PuzzleClearBoardSnapshot,
|
||||
pub ready_columns: Vec<Vec<PuzzleClearCardAssetSnapshot>>,
|
||||
pub started_at_ms: u64,
|
||||
pub finished_at_ms: Option<u64>,
|
||||
}
|
||||
@@ -1412,6 +1412,7 @@ mod tests {
|
||||
height: 1536,
|
||||
})),
|
||||
back_button_asset_json: None,
|
||||
visible: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user