database migration
This commit is contained in:
@@ -1,273 +0,0 @@
|
|||||||
# Database Migration Guide
|
|
||||||
|
|
||||||
This guide shows how to update all databases to use actual SQL storage with Diesel instead of just `prepare_for_sql()`.
|
|
||||||
|
|
||||||
## Status
|
|
||||||
|
|
||||||
✅ **Completed**: ItemDatabase
|
|
||||||
✅ **Completed**: Database tables created (migration)
|
|
||||||
✅ **Completed**: Main.rs integration example
|
|
||||||
|
|
||||||
⏳ **Remaining**: 9 databases need the same updates
|
|
||||||
|
|
||||||
## Pattern to Follow
|
|
||||||
|
|
||||||
For each database file in `src/databases/`, follow this pattern (using ItemDatabase as the reference):
|
|
||||||
|
|
||||||
### Step 1: Add Diesel Imports
|
|
||||||
|
|
||||||
At the top of the file, add:
|
|
||||||
```rust
|
|
||||||
use diesel::prelude::*;
|
|
||||||
use diesel::sqlite::SqliteConnection;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 2: Add `save_to_db()` Method
|
|
||||||
|
|
||||||
Replace or add after the `prepare_for_sql()` method:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
/// Save all [items/npcs/quests/etc] to SQLite database
|
|
||||||
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
|
||||||
use crate::schema::TABLE_NAME; // Replace TABLE_NAME
|
|
||||||
|
|
||||||
let records: Vec<_> = self
|
|
||||||
.ITEMS_FIELD // Replace with actual field name (e.g., items, npcs, quests)
|
|
||||||
.iter()
|
|
||||||
.map(|item| {
|
|
||||||
let json = serde_json::to_string(item).unwrap_or_else(|_| "{}".to_string());
|
|
||||||
(
|
|
||||||
TABLE_NAME::id.eq(item.ID_FIELD), // Replace ID_FIELD
|
|
||||||
TABLE_NAME::name.eq(&item.NAME_FIELD), // Replace NAME_FIELD
|
|
||||||
TABLE_NAME::data.eq(json),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for record in records {
|
|
||||||
diesel::insert_into(TABLE_NAME::table)
|
|
||||||
.values(&record)
|
|
||||||
.execute(conn)?;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(count)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 3: Add `load_from_db()` Method
|
|
||||||
|
|
||||||
```rust
|
|
||||||
/// Load all [items/npcs/quests/etc] from SQLite database
|
|
||||||
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
|
||||||
use crate::schema::TABLE_NAME::dsl::*; // Replace TABLE_NAME
|
|
||||||
|
|
||||||
#[derive(Queryable)]
|
|
||||||
struct Record {
|
|
||||||
id: Option<i32>, // Or Option<String> for text keys
|
|
||||||
name: String, // Adjust based on schema
|
|
||||||
data: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
let records = TABLE_NAME.load::<Record>(conn)?; // Replace TABLE_NAME
|
|
||||||
|
|
||||||
let mut loaded_items = Vec::new();
|
|
||||||
for record in records {
|
|
||||||
if let Ok(item) = serde_json::from_str::<TYPE>(&record.data) { // Replace TYPE
|
|
||||||
loaded_items.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut db = Self::new();
|
|
||||||
db.add_ITEMS(loaded_items); // Replace add_ITEMS with actual method
|
|
||||||
Ok(db)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Step 4: Mark `prepare_for_sql()` as Deprecated
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
|
||||||
pub fn prepare_for_sql(&self) -> Vec<...> {
|
|
||||||
// existing implementation
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database-Specific Mappings
|
|
||||||
|
|
||||||
### Simple Databases (id: i32, name: String, data: String)
|
|
||||||
|
|
||||||
| Database | Table | Items Field | ID Field | Name Field | Type |
|
|
||||||
|----------|-------|-------------|----------|------------|------|
|
|
||||||
| NpcDatabase | `npcs` | `npcs` | `type_id` | `npc_name` | `Npc` |
|
|
||||||
| QuestDatabase | `quests` | `quests` | `id` | `name` | `Quest` |
|
|
||||||
| HarvestableDatabase | `harvestables` | `harvestables` | `type_id` | `name` | `Harvestable` |
|
|
||||||
|
|
||||||
**Example for NpcDatabase:**
|
|
||||||
```rust
|
|
||||||
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
|
||||||
use crate::schema::npcs;
|
|
||||||
|
|
||||||
let records: Vec<_> = self
|
|
||||||
.npcs
|
|
||||||
.iter()
|
|
||||||
.map(|npc| {
|
|
||||||
let json = serde_json::to_string(npc).unwrap_or_else(|_| "{}".to_string());
|
|
||||||
(
|
|
||||||
npcs::id.eq(npc.type_id),
|
|
||||||
npcs::name.eq(&npc.npc_name),
|
|
||||||
npcs::data.eq(json),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for record in records {
|
|
||||||
diesel::insert_into(npcs::table)
|
|
||||||
.values(&record)
|
|
||||||
.execute(conn)?;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(count)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Text-Key Databases
|
|
||||||
|
|
||||||
| Database | Table | Primary Key Field | Type |
|
|
||||||
|----------|-------|-------------------|------|
|
|
||||||
| LootDatabase | `loot_tables` | `table_id: String` | `LootTable` |
|
|
||||||
| MapDatabase | `maps` | `scene_id: String` | `Map` |
|
|
||||||
|
|
||||||
**Example for LootDatabase:**
|
|
||||||
```rust
|
|
||||||
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
|
||||||
use crate::schema::loot_tables;
|
|
||||||
|
|
||||||
let records: Vec<_> = self
|
|
||||||
.loot_tables // Check actual field name
|
|
||||||
.iter()
|
|
||||||
.map(|loot| {
|
|
||||||
let json = serde_json::to_string(loot).unwrap_or_else(|_| "{}".to_string());
|
|
||||||
(
|
|
||||||
loot_tables::table_id.eq(&loot.table_id),
|
|
||||||
loot_tables::npc_id.eq(loot.npc_id.as_ref()), // Optional field
|
|
||||||
loot_tables::data.eq(json),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for record in records {
|
|
||||||
diesel::insert_into(loot_tables::table)
|
|
||||||
.values(&record)
|
|
||||||
.execute(conn)?;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(count)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Complex Databases (Multiple Columns)
|
|
||||||
|
|
||||||
| Database | Table | Additional Columns | Notes |
|
|
||||||
|----------|-------|-------------------|-------|
|
|
||||||
| FastTravelDatabase | `fast_travel_locations` | `map_name: String` | Has map reference |
|
|
||||||
| PlayerHouseDatabase | `player_houses` | `map_id: i32` | Has map ID |
|
|
||||||
| TraitDatabase | `traits` | `description: Option<String>`, `trainer_id: Option<i32>` | Multiple optional fields |
|
|
||||||
| ShopDatabase | `shops` | `unique_items: bool`, `item_count: usize` | Has metadata columns |
|
|
||||||
|
|
||||||
**Example for ShopDatabase:**
|
|
||||||
```rust
|
|
||||||
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
|
||||||
use crate::schema::shops;
|
|
||||||
|
|
||||||
let records: Vec<_> = self
|
|
||||||
.shops
|
|
||||||
.iter()
|
|
||||||
.map(|shop| {
|
|
||||||
let json = serde_json::to_string(shop).unwrap_or_else(|_| "{}".to_string());
|
|
||||||
(
|
|
||||||
shops::id.eq(shop.id),
|
|
||||||
shops::name.eq(&shop.name),
|
|
||||||
shops::unique_items.eq(if shop.unique_items { 1 } else { 0 }),
|
|
||||||
shops::item_count.eq(shop.items.len() as i32),
|
|
||||||
shops::data.eq(json),
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut count = 0;
|
|
||||||
for record in records {
|
|
||||||
diesel::insert_into(shops::table)
|
|
||||||
.values(&record)
|
|
||||||
.execute(conn)?;
|
|
||||||
count += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(count)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage in main.rs
|
|
||||||
|
|
||||||
After loading all databases from XML, save them to SQL:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
// Establish database connection
|
|
||||||
let mut conn = SqliteConnection::establish("cursebreaker.db")?;
|
|
||||||
|
|
||||||
// Save each database
|
|
||||||
match item_db.save_to_db(&mut conn) {
|
|
||||||
Ok(count) => info!("✅ Saved {} items to database", count),
|
|
||||||
Err(e) => warn!("⚠️ Failed to save items: {}", e),
|
|
||||||
}
|
|
||||||
|
|
||||||
match npc_db.save_to_db(&mut conn) {
|
|
||||||
Ok(count) => info!("✅ Saved {} NPCs to database", count),
|
|
||||||
Err(e) => warn!("⚠️ Failed to save NPCs: {}", e),
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... repeat for all databases
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
After implementing for each database:
|
|
||||||
|
|
||||||
1. **Build**: `cargo build` - Should compile without errors
|
|
||||||
2. **Run**: `cargo run` - Should show save confirmations
|
|
||||||
3. **Verify**: Check `cursebreaker.db` contains data
|
|
||||||
|
|
||||||
## Implementation Order Recommendation
|
|
||||||
|
|
||||||
1. ✅ ItemDatabase (DONE)
|
|
||||||
2. NpcDatabase (simple, same as items)
|
|
||||||
3. QuestDatabase (simple, same as items)
|
|
||||||
4. HarvestableDatabase (simple, same as items)
|
|
||||||
5. MapDatabase (text key, medium)
|
|
||||||
6. LootDatabase (text key with optional field, medium)
|
|
||||||
7. FastTravelDatabase (multiple columns, complex)
|
|
||||||
8. PlayerHouseDatabase (multiple columns, complex)
|
|
||||||
9. TraitDatabase (optional columns, complex)
|
|
||||||
10. ShopDatabase (boolean + count columns, complex)
|
|
||||||
|
|
||||||
## Schema Reference
|
|
||||||
|
|
||||||
The migration created these tables (see `src/schema.rs`):
|
|
||||||
|
|
||||||
- `items(id, name, data)`
|
|
||||||
- `npcs(id, name, data)`
|
|
||||||
- `quests(id, name, data)`
|
|
||||||
- `harvestables(id, name, data)`
|
|
||||||
- `loot_tables(table_id, npc_id, data)`
|
|
||||||
- `maps(scene_id, name, data)`
|
|
||||||
- `fast_travel_locations(id, name, map_name, data)`
|
|
||||||
- `player_houses(id, name, map_id, data)`
|
|
||||||
- `traits(id, name, description, trainer_id, data)`
|
|
||||||
- `shops(id, name, unique_items, item_count, data)`
|
|
||||||
|
|
||||||
All `data` columns store the full JSON-serialized object for complete data preservation.
|
|
||||||
@@ -3,6 +3,8 @@ use crate::xml_parser::{
|
|||||||
parse_fast_travel_canoe_xml, parse_fast_travel_locations_xml, parse_fast_travel_portals_xml,
|
parse_fast_travel_canoe_xml, parse_fast_travel_locations_xml, parse_fast_travel_portals_xml,
|
||||||
XmlParseError,
|
XmlParseError,
|
||||||
};
|
};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -234,8 +236,8 @@ impl FastTravelDatabase {
|
|||||||
self.locations.is_empty()
|
self.locations.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare fast travel locations for SQL insertion
|
/// Prepare fast travel locations for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (id, name, type, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String, String)> {
|
||||||
self.locations
|
self.locations
|
||||||
.iter()
|
.iter()
|
||||||
@@ -251,6 +253,61 @@ impl FastTravelDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all fast travel locations to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::fast_travel_locations;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.locations
|
||||||
|
.iter()
|
||||||
|
.map(|location| {
|
||||||
|
let json = serde_json::to_string(location).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
fast_travel_locations::id.eq(location.id),
|
||||||
|
fast_travel_locations::name.eq(&location.name),
|
||||||
|
fast_travel_locations::map_name.eq(""), // TODO: determine actual map name
|
||||||
|
fast_travel_locations::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(fast_travel_locations::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all fast travel locations from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::fast_travel_locations::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct FastTravelLocationRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
map_name: String,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = fast_travel_locations.load::<FastTravelLocationRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_locations = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(location) = serde_json::from_str::<FastTravelLocation>(&record.data) {
|
||||||
|
loaded_locations.push(location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_locations(loaded_locations);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FastTravelDatabase {
|
impl Default for FastTravelDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Harvestable;
|
use crate::types::Harvestable;
|
||||||
use crate::xml_parser::{parse_harvestables_xml, XmlParseError};
|
use crate::xml_parser::{parse_harvestables_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -122,8 +124,8 @@ impl HarvestableDatabase {
|
|||||||
self.harvestables.is_empty()
|
self.harvestables.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare harvestables for SQL insertion
|
/// Prepare harvestables for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (typeid, name, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
||||||
self.harvestables
|
self.harvestables
|
||||||
.iter()
|
.iter()
|
||||||
@@ -133,6 +135,59 @@ impl HarvestableDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.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 {
|
impl Default for HarvestableDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::{LootTable, LootDrop};
|
use crate::types::{LootTable, LootDrop};
|
||||||
use crate::xml_parser::{parse_loot_xml, XmlParseError};
|
use crate::xml_parser::{parse_loot_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -147,8 +149,8 @@ impl LootDatabase {
|
|||||||
self.tables.is_empty()
|
self.tables.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare loot tables for SQL insertion
|
/// Prepare loot tables for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (npc_ids_json, name, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(String, Option<String>, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(String, Option<String>, String)> {
|
||||||
self.tables
|
self.tables
|
||||||
.iter()
|
.iter()
|
||||||
@@ -159,6 +161,54 @@ impl LootDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all loot tables to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::loot_tables;
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for table in &self.tables {
|
||||||
|
let table_id = serde_json::to_string(&table.npc_ids).unwrap_or_else(|_| "[]".to_string());
|
||||||
|
let json = serde_json::to_string(table).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
let record = (
|
||||||
|
loot_tables::table_id.eq(table_id),
|
||||||
|
loot_tables::npc_id.eq(None::<String>),
|
||||||
|
loot_tables::data.eq(json),
|
||||||
|
);
|
||||||
|
|
||||||
|
diesel::insert_into(loot_tables::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all loot tables from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::loot_tables::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct LootTableRecord {
|
||||||
|
table_id: Option<String>,
|
||||||
|
npc_id: Option<String>,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = loot_tables.load::<LootTableRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_tables = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(table) = serde_json::from_str::<LootTable>(&record.data) {
|
||||||
|
loaded_tables.push(table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_tables(loaded_tables);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for LootDatabase {
|
impl Default for LootDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Map;
|
use crate::types::Map;
|
||||||
use crate::xml_parser::{parse_maps_xml, XmlParseError};
|
use crate::xml_parser::{parse_maps_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -176,8 +178,8 @@ impl MapDatabase {
|
|||||||
self.maps.is_empty()
|
self.maps.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare maps for SQL insertion
|
/// Prepare maps for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (scene_id, name, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(String, String, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(String, String, String)> {
|
||||||
self.maps
|
self.maps
|
||||||
.iter()
|
.iter()
|
||||||
@@ -187,6 +189,59 @@ impl MapDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all maps to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::maps;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.maps
|
||||||
|
.iter()
|
||||||
|
.map(|map| {
|
||||||
|
let json = serde_json::to_string(map).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
maps::scene_id.eq(&map.scene_id),
|
||||||
|
maps::name.eq(&map.name),
|
||||||
|
maps::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(maps::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all maps from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::maps::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct MapRecord {
|
||||||
|
scene_id: Option<String>,
|
||||||
|
name: String,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = maps.load::<MapRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_maps = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(map) = serde_json::from_str::<Map>(&record.data) {
|
||||||
|
loaded_maps.push(map);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_maps(loaded_maps);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for MapDatabase {
|
impl Default for MapDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Npc;
|
use crate::types::Npc;
|
||||||
use crate::xml_parser::{parse_npcs_xml, XmlParseError};
|
use crate::xml_parser::{parse_npcs_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -118,8 +120,8 @@ impl NpcDatabase {
|
|||||||
self.npcs.is_empty()
|
self.npcs.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare NPCs for SQL insertion
|
/// Prepare NPCs for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (id, name, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
||||||
self.npcs
|
self.npcs
|
||||||
.iter()
|
.iter()
|
||||||
@@ -129,6 +131,59 @@ impl NpcDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all NPCs to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::npcs;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.npcs
|
||||||
|
.iter()
|
||||||
|
.map(|npc| {
|
||||||
|
let json = serde_json::to_string(npc).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
npcs::id.eq(npc.id),
|
||||||
|
npcs::name.eq(&npc.name),
|
||||||
|
npcs::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(npcs::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all NPCs from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::npcs::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct NpcRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = npcs.load::<NpcRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_npcs = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(npc) = serde_json::from_str::<Npc>(&record.data) {
|
||||||
|
loaded_npcs.push(npc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_npcs(loaded_npcs);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for NpcDatabase {
|
impl Default for NpcDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::PlayerHouse;
|
use crate::types::PlayerHouse;
|
||||||
use crate::xml_parser::{parse_player_houses_xml, XmlParseError};
|
use crate::xml_parser::{parse_player_houses_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -150,8 +152,8 @@ impl PlayerHouseDatabase {
|
|||||||
self.houses.is_empty()
|
self.houses.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare player houses for SQL insertion
|
/// Prepare player houses for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (id, name, price, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, i32, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, i32, String)> {
|
||||||
self.houses
|
self.houses
|
||||||
.iter()
|
.iter()
|
||||||
@@ -161,6 +163,61 @@ impl PlayerHouseDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all player houses to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::player_houses;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.houses
|
||||||
|
.iter()
|
||||||
|
.map(|house| {
|
||||||
|
let json = serde_json::to_string(house).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
player_houses::id.eq(house.id),
|
||||||
|
player_houses::name.eq(&house.name),
|
||||||
|
player_houses::map_id.eq(0), // TODO: determine actual map ID
|
||||||
|
player_houses::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(player_houses::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all player houses from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::player_houses::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct PlayerHouseRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
map_id: i32,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = player_houses.load::<PlayerHouseRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_houses = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(house) = serde_json::from_str::<PlayerHouse>(&record.data) {
|
||||||
|
loaded_houses.push(house);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_houses(loaded_houses);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PlayerHouseDatabase {
|
impl Default for PlayerHouseDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Quest;
|
use crate::types::Quest;
|
||||||
use crate::xml_parser::{parse_quests_xml, XmlParseError};
|
use crate::xml_parser::{parse_quests_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -92,8 +94,8 @@ impl QuestDatabase {
|
|||||||
self.quests.is_empty()
|
self.quests.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare quests for SQL insertion
|
/// Prepare quests for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (id, name, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, String)> {
|
||||||
self.quests
|
self.quests
|
||||||
.iter()
|
.iter()
|
||||||
@@ -103,6 +105,59 @@ impl QuestDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all quests to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::quests;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.quests
|
||||||
|
.iter()
|
||||||
|
.map(|quest| {
|
||||||
|
let json = serde_json::to_string(quest).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
quests::id.eq(quest.id),
|
||||||
|
quests::name.eq(&quest.name),
|
||||||
|
quests::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(quests::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all quests from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::quests::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct QuestRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = quests.load::<QuestRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_quests = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(quest) = serde_json::from_str::<Quest>(&record.data) {
|
||||||
|
loaded_quests.push(quest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_quests(loaded_quests);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for QuestDatabase {
|
impl Default for QuestDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Shop;
|
use crate::types::Shop;
|
||||||
use crate::xml_parser::{parse_shops_xml, XmlParseError};
|
use crate::xml_parser::{parse_shops_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -143,8 +145,8 @@ impl ShopDatabase {
|
|||||||
self.shops.is_empty()
|
self.shops.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare shops for SQL insertion
|
/// Prepare shops for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (shop_id, name, is_general_store, item_count, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, bool, usize, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, bool, usize, String)> {
|
||||||
self.shops
|
self.shops
|
||||||
.iter()
|
.iter()
|
||||||
@@ -160,6 +162,63 @@ impl ShopDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all shops to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::shops;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.shops
|
||||||
|
.iter()
|
||||||
|
.map(|shop| {
|
||||||
|
let json = serde_json::to_string(shop).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
shops::id.eq(shop.shop_id),
|
||||||
|
shops::name.eq(&shop.name),
|
||||||
|
shops::unique_items.eq(if shop.is_general_store { 0 } else { 1 }),
|
||||||
|
shops::item_count.eq(shop.items.len() as i32),
|
||||||
|
shops::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(shops::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all shops from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::shops::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct ShopRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
unique_items: i32,
|
||||||
|
item_count: i32,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = shops.load::<ShopRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_shops = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(shop) = serde_json::from_str::<Shop>(&record.data) {
|
||||||
|
loaded_shops.push(shop);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_shops(loaded_shops);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ShopDatabase {
|
impl Default for ShopDatabase {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
use crate::types::Trait;
|
use crate::types::Trait;
|
||||||
use crate::xml_parser::{parse_traits_xml, XmlParseError};
|
use crate::xml_parser::{parse_traits_xml, XmlParseError};
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
@@ -172,8 +174,8 @@ impl TraitDatabase {
|
|||||||
self.traits.is_empty()
|
self.traits.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepare traits for SQL insertion
|
/// Prepare traits for SQL insertion (deprecated - use save_to_db instead)
|
||||||
/// Returns a vector of tuples (id, name, skill, level, json_data)
|
#[deprecated(note = "Use save_to_db() to save directly to SQLite database")]
|
||||||
pub fn prepare_for_sql(&self) -> Vec<(i32, String, Option<String>, Option<i32>, String)> {
|
pub fn prepare_for_sql(&self) -> Vec<(i32, String, Option<String>, Option<i32>, String)> {
|
||||||
self.traits
|
self.traits
|
||||||
.iter()
|
.iter()
|
||||||
@@ -186,6 +188,63 @@ impl TraitDatabase {
|
|||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save all traits to SQLite database
|
||||||
|
pub fn save_to_db(&self, conn: &mut SqliteConnection) -> Result<usize, diesel::result::Error> {
|
||||||
|
use crate::schema::traits;
|
||||||
|
|
||||||
|
let records: Vec<_> = self
|
||||||
|
.traits
|
||||||
|
.iter()
|
||||||
|
.map(|trait_obj| {
|
||||||
|
let json = serde_json::to_string(trait_obj).unwrap_or_else(|_| "{}".to_string());
|
||||||
|
(
|
||||||
|
traits::id.eq(trait_obj.id),
|
||||||
|
traits::name.eq(&trait_obj.name),
|
||||||
|
traits::description.eq(Some(&trait_obj.description)),
|
||||||
|
traits::trainer_id.eq(None::<i32>), // TODO: determine actual trainer ID
|
||||||
|
traits::data.eq(json),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut count = 0;
|
||||||
|
for record in records {
|
||||||
|
diesel::insert_into(traits::table)
|
||||||
|
.values(&record)
|
||||||
|
.execute(conn)?;
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Load all traits from SQLite database
|
||||||
|
pub fn load_from_db(conn: &mut SqliteConnection) -> Result<Self, diesel::result::Error> {
|
||||||
|
use crate::schema::traits::dsl::*;
|
||||||
|
|
||||||
|
#[derive(Queryable)]
|
||||||
|
struct TraitRecord {
|
||||||
|
id: Option<i32>,
|
||||||
|
name: String,
|
||||||
|
description: Option<String>,
|
||||||
|
trainer_id: Option<i32>,
|
||||||
|
data: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
let records = traits.load::<TraitRecord>(conn)?;
|
||||||
|
|
||||||
|
let mut loaded_traits = Vec::new();
|
||||||
|
for record in records {
|
||||||
|
if let Ok(trait_obj) = serde_json::from_str::<Trait>(&record.data) {
|
||||||
|
loaded_traits.push(trait_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut db = Self::new();
|
||||||
|
db.add_traits(loaded_traits);
|
||||||
|
Ok(db)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for TraitDatabase {
|
impl Default for TraitDatabase {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
//! 3. Extracting typeId and transform positions
|
//! 3. Extracting typeId and transform positions
|
||||||
//! 4. Writing resource data to an output file
|
//! 4. Writing resource data to an output file
|
||||||
|
|
||||||
use cursebreaker_parser::{ItemDatabase, NpcDatabase, QuestDatabase, HarvestableDatabase, LootDatabase, InteractableResource, MinimapDatabase};
|
use cursebreaker_parser::{ItemDatabase, NpcDatabase, QuestDatabase, HarvestableDatabase, LootDatabase, MapDatabase, FastTravelDatabase, PlayerHouseDatabase, TraitDatabase, ShopDatabase, InteractableResource, MinimapDatabase};
|
||||||
use unity_parser::UnityProject;
|
use unity_parser::UnityProject;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use unity_parser::log::DedupLogger;
|
use unity_parser::log::DedupLogger;
|
||||||
@@ -47,6 +47,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
let loot_db = LootDatabase::load_from_xml(loot_path)?;
|
let loot_db = LootDatabase::load_from_xml(loot_path)?;
|
||||||
info!("✅ Loaded {} loot tables", loot_db.len());
|
info!("✅ Loaded {} loot tables", loot_db.len());
|
||||||
|
|
||||||
|
let maps_path = "/home/connor/repos/CBAssets/Data/XMLs/Maps/Maps.xml";
|
||||||
|
let map_db = MapDatabase::load_from_xml(maps_path)?;
|
||||||
|
info!("✅ Loaded {} maps", map_db.len());
|
||||||
|
|
||||||
|
let fast_travel_dir = "/home/connor/repos/CBAssets/Data/XMLs";
|
||||||
|
let fast_travel_db = FastTravelDatabase::load_from_directory(fast_travel_dir)?;
|
||||||
|
info!("✅ Loaded {} fast travel locations", fast_travel_db.len());
|
||||||
|
|
||||||
|
let player_houses_path = "/home/connor/repos/CBAssets/Data/XMLs/PlayerHouses/PlayerHouses.xml";
|
||||||
|
let player_house_db = PlayerHouseDatabase::load_from_xml(player_houses_path)?;
|
||||||
|
info!("✅ Loaded {} player houses", player_house_db.len());
|
||||||
|
|
||||||
|
let traits_path = "/home/connor/repos/CBAssets/Data/XMLs/Traits/Traits.xml";
|
||||||
|
let trait_db = TraitDatabase::load_from_xml(traits_path)?;
|
||||||
|
info!("✅ Loaded {} traits", trait_db.len());
|
||||||
|
|
||||||
|
let shops_path = "/home/connor/repos/CBAssets/Data/XMLs/Shops/Shops.xml";
|
||||||
|
let shop_db = ShopDatabase::load_from_xml(shops_path)?;
|
||||||
|
info!("✅ Loaded {} shops", shop_db.len());
|
||||||
|
|
||||||
// Save to SQLite database
|
// Save to SQLite database
|
||||||
info!("\n💾 Saving game data to SQLite database...");
|
info!("\n💾 Saving game data to SQLite database...");
|
||||||
let mut conn = SqliteConnection::establish("cursebreaker.db")?;
|
let mut conn = SqliteConnection::establish("cursebreaker.db")?;
|
||||||
@@ -56,6 +76,51 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||||||
Err(e) => warn!("⚠️ Failed to save items: {}", e),
|
Err(e) => warn!("⚠️ Failed to save items: {}", e),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
match npc_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} NPCs to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save NPCs: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match quest_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} quests to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save quests: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match harvestable_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} harvestables to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save harvestables: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match loot_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} loot tables to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save loot tables: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match map_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} maps to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save maps: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match fast_travel_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} fast travel locations to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save fast travel locations: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match player_house_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} player houses to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save player houses: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match trait_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} traits to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save traits: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
|
match shop_db.save_to_db(&mut conn) {
|
||||||
|
Ok(count) => info!("✅ Saved {} shops to database", count),
|
||||||
|
Err(e) => warn!("⚠️ Failed to save shops: {}", e),
|
||||||
|
}
|
||||||
|
|
||||||
// Print statistics
|
// Print statistics
|
||||||
info!("\n📊 Game Data Statistics:");
|
info!("\n📊 Game Data Statistics:");
|
||||||
info!(" Items:");
|
info!(" Items:");
|
||||||
|
|||||||
Reference in New Issue
Block a user