198 lines
6.0 KiB
Rust
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()
|
|
}
|
|
}
|