feat: add puzzle clear template runtime

This commit is contained in:
2026-06-03 22:11:46 +08:00
parent 6e74cf5add
commit 1b5e098225
148 changed files with 19588 additions and 241 deletions

View File

@@ -0,0 +1,191 @@
use serde::{Deserialize, Serialize};
#[cfg(feature = "spacetime-types")]
use spacetimedb::SpacetimeType;
pub const PUZZLE_CLEAR_PLAY_ID: &str = "puzzle-clear";
pub const PUZZLE_CLEAR_PUBLIC_WORK_CODE_PREFIX: &str = "PC-";
pub const PUZZLE_CLEAR_SESSION_ID_PREFIX: &str = "puzzle-clear-session-";
pub const PUZZLE_CLEAR_PROFILE_ID_PREFIX: &str = "puzzle-clear-profile-";
pub const PUZZLE_CLEAR_WORK_ID_PREFIX: &str = "puzzle-clear-work-";
pub const PUZZLE_CLEAR_RUN_ID_PREFIX: &str = "puzzle-clear-run-";
pub const PUZZLE_CLEAR_LEVEL_DURATION_SECONDS: u32 = 600;
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PuzzleClearShapeKind {
OneByTwo,
OneByThree,
TwoByTwo,
TwoByThree,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PuzzleClearOrientation {
Horizontal,
Vertical,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum PuzzleClearRunStatus {
Playing,
LevelFailed,
LevelCleared,
Finished,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearLevelConfig {
pub level_index: u32,
pub board_size: u32,
pub target_clears: u32,
pub duration_seconds: u32,
pub unlocked_shapes: Vec<PuzzleClearShapeKind>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearShapeQuota {
pub shape: PuzzleClearShapeKind,
pub count: u32,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearPatternGroup {
pub group_id: String,
pub shape: PuzzleClearShapeKind,
pub width: u32,
pub height: u32,
pub atlas_x: u32,
pub atlas_y: u32,
pub atlas_width: u32,
pub atlas_height: u32,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearCard {
pub card_id: String,
pub group_id: String,
pub shape: PuzzleClearShapeKind,
pub orientation: PuzzleClearOrientation,
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,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearCell {
pub row: u32,
pub col: u32,
pub card: Option<PuzzleClearCard>,
pub locked_group_id: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearBoard {
pub rows: u32,
pub cols: u32,
pub cells: Vec<PuzzleClearCell>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearDeck {
pub ready_columns: Vec<Vec<PuzzleClearCard>>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearMove {
pub from_row: u32,
pub from_col: u32,
pub to_row: u32,
pub to_col: u32,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearElimination {
pub group_id: String,
pub positions: Vec<(u32, u32)>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct PuzzleClearRunSnapshot {
pub run_id: String,
pub owner_user_id: String,
pub profile_id: String,
pub status: PuzzleClearRunStatus,
pub level_index: u32,
pub clears_done: u32,
pub board: PuzzleClearBoard,
pub deck: PuzzleClearDeck,
pub started_at_ms: u64,
pub level_started_at_ms: u64,
pub finished_at_ms: Option<u64>,
}
impl PuzzleClearShapeKind {
pub fn as_str(self) -> &'static str {
match self {
Self::OneByTwo => "1x2",
Self::OneByThree => "1x3",
Self::TwoByTwo => "2x2",
Self::TwoByThree => "2x3",
}
}
pub fn base_dimensions(self) -> (u32, u32) {
match self {
Self::OneByTwo => (2, 1),
Self::OneByThree => (3, 1),
Self::TwoByTwo => (2, 2),
Self::TwoByThree => (3, 2),
}
}
pub fn dimensions(self, orientation: PuzzleClearOrientation) -> (u32, u32) {
let (width, height) = self.base_dimensions();
if matches!(orientation, PuzzleClearOrientation::Vertical)
&& matches!(
self,
PuzzleClearShapeKind::OneByTwo
| PuzzleClearShapeKind::OneByThree
| PuzzleClearShapeKind::TwoByThree
)
{
(height, width)
} else {
(width, height)
}
}
}
impl PuzzleClearOrientation {
pub fn as_str(self) -> &'static str {
match self {
Self::Horizontal => "horizontal",
Self::Vertical => "vertical",
}
}
}
impl PuzzleClearRunStatus {
pub fn as_str(self) -> &'static str {
match self {
Self::Playing => "playing",
Self::LevelFailed => "level_failed",
Self::LevelCleared => "level_cleared",
Self::Finished => "finished",
}
}
}