Files
cursebreaker-parser-rust/cursebreaker-parser/src/databases/harvestable_database.rs
2026-01-10 09:22:58 +00:00

198 lines
6.0 KiB
Rust

use crate::types::Harvestable;
use crate::xml_parser::{parse_harvestables_xml, XmlParseError};
use diesel::prelude::*;
use diesel::sqlite::SqliteConnection;
use std::collections::HashMap;
use std::path::Path;
/// A database for managing Harvestables loaded from XML files
#[derive(Debug, Clone)]
pub struct HarvestableDatabase {
harvestables: Vec<Harvestable>,
harvestables_by_typeid: HashMap<i32, usize>,
harvestables_by_name: HashMap<String, usize>,
}
impl HarvestableDatabase {
/// Create a new empty HarvestableDatabase
pub fn new() -> Self {
Self {
harvestables: Vec::new(),
harvestables_by_typeid: HashMap::new(),
harvestables_by_name: HashMap::new(),
}
}
/// Load harvestables from an XML file
pub fn load_from_xml<P: AsRef<Path>>(path: P) -> Result<Self, XmlParseError> {
let harvestables = parse_harvestables_xml(path)?;
let mut db = Self::new();
db.add_harvestables(harvestables);
Ok(db)
}
/// Add harvestables to the database
pub fn add_harvestables(&mut self, harvestables: Vec<Harvestable>) {
for harvestable in harvestables {
let index = self.harvestables.len();
self.harvestables_by_typeid.insert(harvestable.typeid, index);
self.harvestables_by_name.insert(harvestable.name.clone(), index);
self.harvestables.push(harvestable);
}
}
/// Get a harvestable by type ID
pub fn get_by_typeid(&self, typeid: i32) -> Option<&Harvestable> {
self.harvestables_by_typeid
.get(&typeid)
.and_then(|&index| self.harvestables.get(index))
}
/// Get a harvestable by name
pub fn get_by_name(&self, name: &str) -> Option<&Harvestable> {
self.harvestables_by_name
.get(name)
.and_then(|&index| self.harvestables.get(index))
}
/// Get all harvestables
pub fn all_harvestables(&self) -> &[Harvestable] {
&self.harvestables
}
/// Get harvestables by skill
pub fn get_by_skill(&self, skill: &str) -> Vec<&Harvestable> {
self.harvestables
.iter()
.filter(|h| {
h.skill
.as_ref()
.map(|s| s.eq_ignore_ascii_case(skill))
.unwrap_or(false)
})
.collect()
}
/// Get harvestables that require a specific tool
pub fn get_by_tool(&self, tool: &str) -> Vec<&Harvestable> {
self.harvestables
.iter()
.filter(|h| {
h.tool
.as_ref()
.map(|t| t.eq_ignore_ascii_case(tool))
.unwrap_or(false)
})
.collect()
}
/// Get all trees (harvestables with tree=1)
pub fn get_trees(&self) -> Vec<&Harvestable> {
self.harvestables
.iter()
.filter(|h| h.is_tree())
.collect()
}
/// Get harvestables that require tools
pub fn get_requiring_tools(&self) -> Vec<&Harvestable> {
self.harvestables
.iter()
.filter(|h| h.requires_tool())
.collect()
}
/// Get harvestables by level range
pub fn get_by_level_range(&self, min_level: i32, max_level: i32) -> Vec<&Harvestable> {
self.harvestables
.iter()
.filter(|h| {
h.level
.map(|l| l >= min_level && l <= max_level)
.unwrap_or(false)
})
.collect()
}
/// Get number of harvestables in database
pub fn len(&self) -> usize {
self.harvestables.len()
}
/// Check if database is empty
pub fn is_empty(&self) -> bool {
self.harvestables.is_empty()
}
/// Prepare harvestables for SQL insertion (deprecated - use save_to_db instead)
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
self.harvestables
.iter()
.map(|harvestable| {
let json = serde_json::to_string(harvestable).unwrap_or_else(|_| "{}".to_string());
(harvestable.typeid, harvestable.name.clone(), json)
})
.collect()
}
/// Save all harvestables to SQLite database
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
use crate::schema::harvestables;
let records: Vec<_> = self
.harvestables
.iter()
.map(|harvestable| {
let json = serde_json::to_string(harvestable).unwrap_or_else(|_| "{}".to_string());
(
harvestables::id.eq(harvestable.typeid),
harvestables::name.eq(&harvestable.name),
harvestables::data.eq(json),
)
})
.collect();
let mut count = 0;
for record in records {
diesel::insert_into(harvestables::table)
.values(&record)
.execute(conn)?;
count += 1;
}
Ok(count)
}
/// Load all harvestables from SQLite database
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
use crate::schema::harvestables::dsl::*;
#[derive(Queryable)]
struct HarvestableRecord {
id: Option<i32>,
name: String,
data: String,
}
let records = harvestables.load::<HarvestableRecord>(conn)?;
let mut loaded_harvestables = Vec::new();
for record in records {
if let Ok(harvestable) = serde_json::from_str::<Harvestable>(&record.data) {
loaded_harvestables.push(harvestable);
}
}
let mut db = Self::new();
db.add_harvestables(loaded_harvestables);
Ok(db)
}
}
impl Default for HarvestableDatabase {
fn default() -> Self {
Self::new()
}
}