eternalfest_core 0.18.2

Core crate for Eternalfest
Documentation
use crate::core::{BoundedVec, Instant, SimpleSemVer};
use crate::game::{FamiliesString, GameChannelKey, GameIdRef, GameModeKey, GameOptionKey};
use crate::user::ShortUser;
use async_trait::async_trait;
use auto_impl::auto_impl;
use etwin_core::core::LocaleId;
use etwin_core::declare_new_uuid;
pub use etwin_core::hammerfest::HammerfestItemId;
use etwin_core::types::AnyError;
use etwin_core::user::UserIdRef;
#[cfg(feature = "serde")]
use etwin_serde_tools::{Deserialize, Serialize};
pub use serde_json::Value as JsonValue;
use std::collections::BTreeMap;
use uuid::Uuid;

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
  feature = "serde",
  derive(Serialize, Deserialize),
  serde(tag = "type", rename = "Run")
)]
pub struct Run {
  pub id: RunId,
  pub created_at: Instant,
  pub started_at: Option<Instant>,
  pub result: Option<RunResult>,
  pub game: GameIdRef,
  pub user: ShortUser,
  pub game_mode: GameModeKey,
  pub game_options: Vec<GameOptionKey>,
  pub settings: RunSettings,
}

declare_new_uuid! {
  pub struct RunId(Uuid);
  pub type ParseError = RunIdParseError;
  const SQL_NAME = "run_id";
}

#[cfg_attr(
  feature = "serde",
  derive(Serialize, Deserialize),
  serde(tag = "type", rename = "Run")
)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct RunIdRef {
  pub id: RunId,
}

impl RunIdRef {
  pub const fn new(id: RunId) -> Self {
    Self { id }
  }
}

impl From<RunId> for RunIdRef {
  fn from(id: RunId) -> Self {
    Self::new(id)
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RunResult {
  pub created_at: Instant,
  pub is_victory: bool,
  pub max_level: u32,
  pub scores: BoundedVec<u32, 1, 2>,
  pub items: BTreeMap<HammerfestItemId, u32>,
  pub stats: JsonValue,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RunSettings {
  pub detail: bool,
  pub shake: bool,
  pub sound: bool,
  pub music: bool,
  pub volume: i32,
  pub locale: LocaleId,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct GetUserItems {
  pub user: UserIdRef,
  pub game: GameIdRef,
  pub channel: GameChannelKey,
}

#[derive(Debug, thiserror::Error)]
pub enum GetUserItemsError {
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl GetUserItemsError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct CreateRunOptions {
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub version: SimpleSemVer,
  pub user: UserIdRef,
  pub game_mode: GameModeKey,
  pub game_options: Vec<GameOptionKey>,
  pub settings: RunSettings,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreCreateRun {
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub version: SimpleSemVer,
  pub user: UserIdRef,
  pub mode: GameModeKey,
  pub options: Vec<GameOptionKey>,
  pub settings: RunSettings,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreRun {
  pub id: RunId,
  pub created_at: Instant,
  pub started_at: Option<Instant>,
  pub result: Option<RunResult>,
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub version: SimpleSemVer,
  pub user: UserIdRef,
  pub mode: GameModeKey,
  pub options: Vec<GameOptionKey>,
  pub settings: RunSettings,
}

#[derive(Debug, thiserror::Error)]
pub enum StoreCreateRunError {
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl StoreCreateRunError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreGetRun {
  pub run: RunIdRef,
}

#[derive(Debug, thiserror::Error)]
pub enum StoreGetRunError {
  #[error("run not found")]
  NotFound,
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl StoreGetRunError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreStartRun {
  pub run: RunIdRef,
  pub if_user: UserIdRef,
}

#[derive(Debug, thiserror::Error)]
pub enum StoreStartRunError {
  #[error("run not found")]
  NotFound,
  #[error("invalid user: run created by {created_by:?} but trying started by {started_by:?}")]
  InvalidUser {
    created_by: UserIdRef,
    started_by: UserIdRef,
  },
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl StoreStartRunError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RunStart {
  pub run: RunIdRef,
  pub key: Uuid,
  pub families: FamiliesString,
  pub items: BTreeMap<HammerfestItemId, u32>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct SetRunResultOptions {
  pub is_victory: bool,
  pub max_level: u32,
  pub scores: BoundedVec<u32, 1, 2>,
  pub items: BTreeMap<HammerfestItemId, u32>,
  pub stats: JsonValue,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreSetRunResult {
  pub run: RunIdRef,
  pub if_user: UserIdRef,
  pub is_victory: bool,
  pub max_level: u32,
  pub scores: BoundedVec<u32, 1, 2>,
  pub items: BTreeMap<HammerfestItemId, u32>,
  pub stats: JsonValue,
}

#[derive(Debug, thiserror::Error)]
pub enum StoreSetRunResultError {
  #[error("run not found")]
  NotFound,
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl StoreSetRunResultError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreGetLeaderboard {
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub mode: GameModeKey,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreLeaderboard {
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub mode: GameModeKey,
  // TODO: Listing<LeaderboardEntry>
  pub results: Vec<StoreLeaderboardEntry>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Leaderboard {
  pub game: GameIdRef,
  pub channel: GameChannelKey,
  pub mode: GameModeKey,
  // TODO: Listing<LeaderboardEntry>
  pub results: Vec<LeaderboardEntry>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct StoreLeaderboardEntry {
  pub score: u32,
  pub user: UserIdRef,
  pub run: LeaderboardEntryRun,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct LeaderboardEntry {
  pub score: u32,
  pub user: ShortUser,
  pub run: LeaderboardEntryRun,
}

#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(
  feature = "serde",
  derive(Serialize, Deserialize),
  serde(tag = "type", rename = "Run")
)]
pub struct LeaderboardEntryRun {
  pub id: RunId,
  pub max_level: u32,
  pub game_options: Vec<GameOptionKey>,
}

#[derive(Debug, thiserror::Error)]
pub enum StoreGetLeaderboardError {
  #[error("game not found")]
  GameNotFound,
  #[error(transparent)]
  Other(#[from] AnyError),
}

impl StoreGetLeaderboardError {
  pub fn other<E>(e: E) -> Self
  where
    E: ::std::error::Error + Send + Sync + 'static,
  {
    Self::Other(Box::new(e))
  }
}

#[async_trait]
#[auto_impl(&, Arc)]
pub trait RunStore: Send + Sync {
  async fn get_user_items(&self, req: &GetUserItems) -> Result<BTreeMap<HammerfestItemId, u32>, GetUserItemsError>;

  async fn create_run(&self, req: &StoreCreateRun) -> Result<StoreRun, StoreCreateRunError>;

  async fn get_run(&self, req: &StoreGetRun) -> Result<StoreRun, StoreGetRunError>;

  async fn start_run(&self, req: &StoreStartRun) -> Result<RunStart, StoreStartRunError>;

  async fn set_run_result(&self, req: &StoreSetRunResult) -> Result<StoreRun, StoreSetRunResultError>;

  async fn get_leaderboard(&self, req: &StoreGetLeaderboard) -> Result<StoreLeaderboard, StoreGetLeaderboardError>;
}