Initial commit: OpenFUT Core
Offline Ultimate Team backend — game-independent REST API. - 19 API endpoints: auth, profiles, clubs, cards, packs, squads, objectives, SBCs, match rewards, NPC market, statistics - Axum + SQLite + SQLx with full migrations - Weighted pack generator, SBC validation engine - JSON-driven mod data (cards, packs, objectives, SBCs) - 5 integration tests passing Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
use crate::models::card::CardDefinition;
|
||||
use anyhow::{Context, Result};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
/// In-memory card registry loaded from data/cards/*.json
|
||||
pub struct CardDb {
|
||||
pub cards: HashMap<String, CardDefinition>,
|
||||
}
|
||||
|
||||
impl CardDb {
|
||||
pub fn load(data_dir: &str) -> Result<Self> {
|
||||
let cards_dir = Path::new(data_dir).join("cards");
|
||||
let mut cards = HashMap::new();
|
||||
|
||||
if !cards_dir.exists() {
|
||||
tracing::warn!("Card data directory not found: {:?}", cards_dir);
|
||||
return Ok(Self { cards });
|
||||
}
|
||||
|
||||
for entry in std::fs::read_dir(&cards_dir)
|
||||
.with_context(|| format!("reading cards dir {:?}", cards_dir))?
|
||||
{
|
||||
let entry = entry?;
|
||||
let path = entry.path();
|
||||
if path.extension().map(|e| e == "json").unwrap_or(false) {
|
||||
let content = std::fs::read_to_string(&path)
|
||||
.with_context(|| format!("reading {:?}", path))?;
|
||||
let batch: Vec<CardDefinition> = serde_json::from_str(&content)
|
||||
.with_context(|| format!("parsing {:?}", path))?;
|
||||
for card in batch {
|
||||
cards.insert(card.id.clone(), card);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tracing::info!("Loaded {} card definitions", cards.len());
|
||||
Ok(Self { cards })
|
||||
}
|
||||
|
||||
pub fn get(&self, id: &str) -> Option<&CardDefinition> {
|
||||
self.cards.get(id)
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn by_rarity(&self, rarity: &str) -> Vec<&CardDefinition> {
|
||||
self.cards
|
||||
.values()
|
||||
.filter(|c| {
|
||||
let r = format!("{:?}", c.rarity).to_lowercase();
|
||||
r == rarity || rarity == "any"
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn all(&self) -> Vec<&CardDefinition> {
|
||||
self.cards.values().collect()
|
||||
}
|
||||
|
||||
pub fn by_min_overall(&self, min: u8) -> Vec<&CardDefinition> {
|
||||
self.cards.values().filter(|c| c.overall >= min).collect()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user