Files
Genarrative/server-rs/crates/module-match3d/src/domain.rs
T
JenkenB ae014ac881 Switch to VectorEngine gpt-image-2 and edits
Replace uses of the legacy `gpt-image-2-all` model with `gpt-image-2` and standardize image workflows: no-reference generation uses POST /v1/images/generations, any-reference flows use POST /v1/images/edits with multipart `image` parts. Update SKILLs, generation scripts, decision logs, and docs to reflect the contract change and edits-vs-generations guidance. Apply corresponding changes across backend (api-server match3d/puzzle modules, openai image adapter, mappers, telemetry, spacetime client/module), frontend components and services (Match3D, Puzzle, CreativeImageInputPanel, runtime shells), and add new spritesheet/parser files and tests. Also add media/logo.png. These changes align repository code and documentation with the VectorEngine image API contract and update generation/upload handling (green-screen -> alpha processing, spritesheet handling, and related tests).
2026-05-22 03:06:41 +08:00

269 lines
8.0 KiB
Rust

use serde::{Deserialize, Serialize};
#[cfg(feature = "spacetime-types")]
use spacetimedb::SpacetimeType;
pub const MATCH3D_SESSION_ID_PREFIX: &str = "match3d-session-";
pub const MATCH3D_MESSAGE_ID_PREFIX: &str = "match3d-message-";
pub const MATCH3D_PROFILE_ID_PREFIX: &str = "match3d-profile-";
pub const MATCH3D_WORK_ID_PREFIX: &str = "match3d-work-";
pub const MATCH3D_RUN_ID_PREFIX: &str = "match3d-run-";
pub const MATCH3D_TRAY_SLOT_COUNT: u32 = 7;
pub const MATCH3D_ITEMS_PER_CLEAR: u32 = 3;
pub const MATCH3D_MAX_ITEM_TYPE_COUNT: u32 = 20;
pub(crate) const MATCH3D_MAX_ITEM_TYPE_COUNT_USIZE: usize = 20;
pub const MATCH3D_MIN_DIFFICULTY: u32 = 1;
pub const MATCH3D_MAX_DIFFICULTY: u32 = 10;
pub const MATCH3D_DEFAULT_DURATION_LIMIT_MS: u64 = 10 * 60 * 1000;
pub const MATCH3D_BOARD_CENTER: f32 = 0.5;
pub const MATCH3D_BOARD_RADIUS: f32 = 0.5;
pub const MATCH3D_BOARD_SAFE_MARGIN: f32 = 0.035;
// 中文注释:默认资源池对齐抓大鹅 10*10 物品 Sprite 的 20 种物品上限。
pub(crate) const MATCH3D_BLOCK_VISUAL_KEYS: [&str; MATCH3D_MAX_ITEM_TYPE_COUNT_USIZE] = [
"block-red-2x4",
"block-blue-1x2",
"block-yellow-2x2",
"block-green-1x4",
"block-orange-1x6",
"block-white-1x1",
"block-black-1x8",
"block-tan-2x3",
"block-darkred-2x2",
"block-blue-1x4",
"block-pink-2x4",
"block-gray-1x6",
"block-lavender-tile-2x2",
"block-teal-tile-1x3",
"block-orange-tile-2x2-stud",
"block-purple-slope-1x2",
"block-green-cylinder",
"block-clear-ring",
"block-mint-arch",
"block-gold-cone",
];
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DCreationStage {
CollectingConfig,
DraftReady,
ReadyToPublish,
Published,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DPublicationStatus {
Draft,
Published,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DRunStatus {
Running,
Won,
Failed,
Stopped,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DFailureReason {
TimeUp,
TrayFull,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DItemState {
InBoard,
InTray,
Cleared,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum Match3DClickRejectReason {
RunNotActive,
SnapshotVersionMismatch,
ItemNotFound,
ItemNotInBoard,
ItemNotClickable,
TrayFull,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match3DCreatorConfig {
pub theme_text: String,
pub reference_image_src: Option<String>,
pub clear_count: u32,
pub difficulty: u32,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match3DResultDraft {
pub game_name: String,
pub theme_text: String,
pub summary: String,
pub tags: Vec<String>,
pub cover_image_src: Option<String>,
pub reference_image_src: Option<String>,
pub clear_count: u32,
pub difficulty: u32,
pub publish_ready: bool,
pub blockers: Vec<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match3DWorkProfile {
pub work_id: String,
pub profile_id: String,
pub owner_user_id: String,
pub source_session_id: Option<String>,
pub game_name: String,
pub theme_text: String,
pub summary: String,
pub tags: Vec<String>,
pub cover_image_src: Option<String>,
pub reference_image_src: Option<String>,
pub clear_count: u32,
pub difficulty: u32,
pub publication_status: Match3DPublicationStatus,
pub play_count: u32,
pub updated_at_micros: i64,
pub published_at_micros: Option<i64>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Match3DItemSnapshot {
pub item_instance_id: String,
pub item_type_id: String,
pub visual_key: String,
pub x: f32,
pub y: f32,
pub radius: f32,
pub layer: u32,
pub state: Match3DItemState,
pub clickable: bool,
pub tray_slot_index: Option<u32>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match3DTraySlot {
pub slot_index: u32,
pub item_instance_id: Option<String>,
pub item_type_id: Option<String>,
pub visual_key: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Match3DRunSnapshot {
pub run_id: String,
pub profile_id: String,
pub owner_user_id: String,
pub status: Match3DRunStatus,
pub started_at_ms: u64,
pub duration_limit_ms: u64,
pub remaining_ms: u64,
pub clear_count: u32,
pub total_item_count: u32,
pub cleared_item_count: u32,
/// 领域内部权威快照版本;HTTP DTO 对外映射为 snapshotVersion。
pub board_version: u64,
pub items: Vec<Match3DItemSnapshot>,
pub tray_slots: Vec<Match3DTraySlot>,
pub failure_reason: Option<Match3DFailureReason>,
pub last_confirmed_action_id: Option<String>,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Match3DClickInput {
pub run_id: String,
pub owner_user_id: String,
pub item_instance_id: String,
pub client_action_id: String,
pub snapshot_version: u64,
pub clicked_at_ms: u64,
}
#[cfg_attr(feature = "spacetime-types", derive(SpacetimeType))]
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Match3DClickConfirmation {
pub accepted: bool,
pub reject_reason: Option<Match3DClickRejectReason>,
pub entered_slot_index: Option<u32>,
pub cleared_item_instance_ids: Vec<String>,
pub run: Match3DRunSnapshot,
}
impl Match3DCreationStage {
pub fn as_str(self) -> &'static str {
match self {
Self::CollectingConfig => "collecting_config",
Self::DraftReady => "draft_ready",
Self::ReadyToPublish => "ready_to_publish",
Self::Published => "published",
}
}
}
impl Match3DPublicationStatus {
pub fn as_str(self) -> &'static str {
match self {
Self::Draft => "draft",
Self::Published => "published",
}
}
}
impl Match3DRunStatus {
pub fn as_str(self) -> &'static str {
match self {
Self::Running => "running",
Self::Won => "won",
Self::Failed => "failed",
Self::Stopped => "stopped",
}
}
}
impl Match3DFailureReason {
pub fn as_str(self) -> &'static str {
match self {
Self::TimeUp => "time_up",
Self::TrayFull => "tray_full",
}
}
}
impl Match3DItemState {
pub fn as_str(self) -> &'static str {
match self {
Self::InBoard => "in_board",
Self::InTray => "in_tray",
Self::Cleared => "cleared",
}
}
}
impl Match3DClickRejectReason {
pub fn as_str(self) -> &'static str {
match self {
Self::RunNotActive => "run_not_active",
Self::SnapshotVersionMismatch => "snapshot_version_mismatch",
Self::ItemNotFound => "item_not_found",
Self::ItemNotInBoard => "item_not_in_board",
Self::ItemNotClickable => "item_not_clickable",
Self::TrayFull => "tray_full",
}
}
}