scroll.server/crates/game-service/src/catalog.rs
WiseDev d25a6de423 move all crates into crates/, glob members
pure move, no code touched. readme and protocol.md paths fixed up.
2026-08-23 08:15:45 +03:00

109 lines
3.8 KiB
Rust

use std::path::Path;
use std::sync::Arc;
use logic::{table, LogicDataRef, LogicDataTables};
use crate::config::{CardRef, DataSelector};
pub const GOLD_RESOURCE_FALLBACK_INSTANCE: i32 = 1;
pub const ARENA_FALLBACK_INSTANCE: i32 = 1;
pub struct Catalog {
tables: Arc<LogicDataTables>,
}
impl Catalog {
pub fn empty() -> Self {
Self {
tables: Arc::new(LogicDataTables::empty()),
}
}
pub fn load(root: Option<&Path>) -> Self {
let Some(root) = root else {
tracing::info!("no csv root configured, starter profiles must use explicit table ids");
return Self::empty();
};
match LogicDataTables::load_from_dir(root) {
Ok(tables) => {
tracing::info!(
root = %root.display(),
loaded = tables.loaded_files().len(),
skipped = tables.skipped_files().len(),
"logic data tables loaded"
);
let tables = Arc::new(tables);
if !LogicDataTables::install(Arc::clone(&tables)) {
tracing::warn!("data tables were already installed for this process");
}
Self { tables }
}
Err(error) => {
tracing::warn!(root = %root.display(), %error, "falling back to explicit table ids");
Self::empty()
}
}
}
pub fn tables(&self) -> &LogicDataTables {
&self.tables
}
pub fn is_loaded(&self) -> bool {
self.tables.is_loaded()
}
pub fn resolve_card(&self, card: &CardRef) -> Option<LogicDataRef> {
match card {
CardRef::Explicit { table, instance } => Some(LogicDataRef::of(*table, *instance)),
CardRef::Named(name) => {
let resolved = LogicDataRef::by_name(table::SPELLS, name);
if resolved.is_none() {
tracing::warn!(card = %name, "unknown card name, dropping it from the profile");
return None;
}
Some(resolved)
}
}
}
pub fn resolve(
&self,
selector: &DataSelector,
table_index: i32,
fallback: i32,
) -> LogicDataRef {
match selector {
DataSelector::Instance(instance) => LogicDataRef::of(table_index, *instance),
DataSelector::Named(name) => {
let resolved = LogicDataRef::by_name(table_index, name);
if resolved.is_none() {
tracing::warn!(
name = %name,
table = table_index,
fallback,
"unknown data name, using the fallback instance"
);
return LogicDataRef::of(table_index, fallback);
}
resolved
}
}
}
pub fn card_pool(&self) -> Vec<LogicDataRef> {
const CARD_TABLES: [i32; 3] = [
table::SPELLS_CHARACTERS,
table::SPELLS_BUILDINGS,
table::SPELLS_OTHER,
];
let mut pool = Vec::new();
for card_table in CARD_TABLES {
let Some(rows) = self.tables.table(card_table) else {
continue;
};
for row in rows.iter() {
if row.boolean("NotInUse") {
continue;
}
pool.push(LogicDataRef::from(std::sync::Arc::clone(row)));
}
}
pool
}
pub fn resolve_arena(&self, selector: &DataSelector) -> LogicDataRef {
self.resolve(selector, table::ARENAS, ARENA_FALLBACK_INSTANCE)
}
pub fn resolve_resource(&self, selector: &DataSelector) -> LogicDataRef {
self.resolve(selector, table::RESOURCES, GOLD_RESOURCE_FALLBACK_INSTANCE)
}
}