Implement auth, persistence, typed responses, and injectable RNG
Auth: JWT tokens (sb-auth) with argon2 password hashing, login/register endpoints, Bearer token middleware protecting all routes except auth. Authorization checks ensure users can only access their own characters. Persistence: SQLite via rusqlite (sb-db) with write-through on all mutations. Optional via SB_DB_PATH env var; falls back to in-memory. Typed responses: ~20 response DTOs in sb-shared replacing ad-hoc JSON. Combat: Injectable RNG via &mut impl Rng for deterministic tests. Clean Architecture: Combat types and response DTOs in sb-shared; domain services in sb-core; auth in sb-auth; persistence in sb-db.
This commit is contained in:
parent
7a75a523f0
commit
6410e0a86d
39 changed files with 3450 additions and 48 deletions
63
crates/sb-core/src/data.rs
Normal file
63
crates/sb-core/src/data.rs
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
use serde::{Deserialize, Serialize};
|
||||
|
||||
const ENEMIES_JSON: &str =
|
||||
include_str!("../../../../skara-brae-common/data/enemies.json");
|
||||
const ZONES_JSON: &str =
|
||||
include_str!("../../../../skara-brae-common/data/adventures/zones.json");
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnemyDef {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub level: i32,
|
||||
pub stats: EnemyStats,
|
||||
pub hp: i32,
|
||||
pub attack_type: String,
|
||||
pub damage: i32,
|
||||
pub defense: i32,
|
||||
pub xp: i32,
|
||||
pub gold_min: i32,
|
||||
pub gold_max: i32,
|
||||
pub loot: Vec<LootDrop>,
|
||||
pub description: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct LootDrop {
|
||||
pub item_id: String,
|
||||
pub chance: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EnemyStats {
|
||||
pub strength: i64,
|
||||
pub intelligence: i64,
|
||||
pub dexterity: i64,
|
||||
pub constitution: i64,
|
||||
pub luck: i64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct EncounterEntry {
|
||||
pub enemy_id: String,
|
||||
pub weight: i32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct ZoneDef {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub min_level: i32,
|
||||
pub max_level: i32,
|
||||
pub nerve_cost: i32,
|
||||
pub description: String,
|
||||
pub encounters: Vec<EncounterEntry>,
|
||||
}
|
||||
|
||||
pub fn load_enemies() -> Vec<EnemyDef> {
|
||||
serde_json::from_str(ENEMIES_JSON).expect("failed to parse enemies.json")
|
||||
}
|
||||
|
||||
pub fn load_zones() -> Vec<ZoneDef> {
|
||||
serde_json::from_str(ZONES_JSON).expect("failed to parse zones.json")
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue