world resources to DB
This commit is contained in:
@@ -37,7 +37,8 @@
|
||||
"Bash(DATABASE_URL=../cursebreaker.db diesel migration:*)",
|
||||
"Bash(DATABASE_URL=cursebreaker.db diesel migration:*)",
|
||||
"Bash(DATABASE_URL=../cursebreaker-parser/cursebreaker.db cargo run:*)",
|
||||
"Bash(identify:*)"
|
||||
"Bash(identify:*)",
|
||||
"Bash(diesel migration revert:*)"
|
||||
],
|
||||
"additionalDirectories": [
|
||||
"/home/connor/repos/CBAssets/"
|
||||
|
||||
59
cursebreaker-parser/examples/query_world_resources.rs
Normal file
59
cursebreaker-parser/examples/query_world_resources.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
//! Example: Query world resources from the database
|
||||
//!
|
||||
//! Run with: cargo run --example query_world_resources
|
||||
|
||||
use diesel::prelude::*;
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
use std::env;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
// Connect to database
|
||||
let database_url = env::var("DATABASE_URL").unwrap_or_else(|_| "../cursebreaker.db".to_string());
|
||||
let mut conn = SqliteConnection::establish(&database_url)?;
|
||||
|
||||
// Use the schema
|
||||
use cursebreaker_parser::schema::world_resources::dsl::*;
|
||||
|
||||
// Query all resources
|
||||
#[derive(Queryable, Debug)]
|
||||
struct WorldResource {
|
||||
item_id: i32,
|
||||
pos_x: f32,
|
||||
pos_y: f32,
|
||||
}
|
||||
|
||||
let results = world_resources
|
||||
.limit(10)
|
||||
.load::<WorldResource>(&mut conn)?;
|
||||
|
||||
println!("Found {} resources (showing first 10):", results.len());
|
||||
println!();
|
||||
|
||||
for resource in results {
|
||||
println!("Resource:");
|
||||
println!(" Item ID: {}", resource.item_id);
|
||||
println!(" Position: ({:.2}, {:.2})", resource.pos_x, resource.pos_y);
|
||||
println!();
|
||||
}
|
||||
|
||||
// Query all resources
|
||||
println!("\n--- All world resources ---");
|
||||
let all_results = world_resources
|
||||
.load::<WorldResource>(&mut conn)?;
|
||||
|
||||
println!("Found {} total resources", all_results.len());
|
||||
|
||||
// Group by item_id
|
||||
use std::collections::HashMap;
|
||||
let mut item_counts: HashMap<i32, usize> = HashMap::new();
|
||||
for resource in &all_results {
|
||||
*item_counts.entry(resource.item_id).or_insert(0) += 1;
|
||||
}
|
||||
|
||||
println!("\nResource counts by item ID:");
|
||||
for (i_id, count) in item_counts {
|
||||
println!(" Item {}: {} instances", i_id, count);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
DROP TABLE world_resources;
|
||||
@@ -0,0 +1,14 @@
|
||||
-- World resources table - stores harvestable resources from Unity scenes
|
||||
CREATE TABLE world_resources (
|
||||
id INTEGER PRIMARY KEY,
|
||||
item_id INTEGER NOT NULL,
|
||||
scene_name TEXT NOT NULL,
|
||||
pos_x REAL NOT NULL,
|
||||
pos_y REAL NOT NULL,
|
||||
pos_z REAL NOT NULL,
|
||||
object_name TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_world_resources_item_id ON world_resources(item_id);
|
||||
CREATE INDEX idx_world_resources_scene ON world_resources(scene_name);
|
||||
CREATE INDEX idx_world_resources_position ON world_resources(pos_x, pos_z);
|
||||
@@ -0,0 +1,16 @@
|
||||
-- Revert to original structure
|
||||
DROP TABLE world_resources;
|
||||
|
||||
CREATE TABLE world_resources (
|
||||
id INTEGER PRIMARY KEY,
|
||||
item_id INTEGER NOT NULL,
|
||||
scene_name TEXT NOT NULL,
|
||||
pos_x REAL NOT NULL,
|
||||
pos_y REAL NOT NULL,
|
||||
pos_z REAL NOT NULL,
|
||||
object_name TEXT NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX idx_world_resources_item_id ON world_resources(item_id);
|
||||
CREATE INDEX idx_world_resources_scene ON world_resources(scene_name);
|
||||
CREATE INDEX idx_world_resources_position ON world_resources(pos_x, pos_z);
|
||||
@@ -0,0 +1,13 @@
|
||||
-- Drop the old table
|
||||
DROP TABLE world_resources;
|
||||
|
||||
-- Recreate with simplified structure - no id, no scene_name, no object_name, only 2D coordinates
|
||||
CREATE TABLE world_resources (
|
||||
item_id INTEGER NOT NULL,
|
||||
pos_x REAL NOT NULL,
|
||||
pos_y REAL NOT NULL,
|
||||
PRIMARY KEY (item_id, pos_x, pos_y)
|
||||
) WITHOUT ROWID;
|
||||
|
||||
CREATE INDEX idx_world_resources_item_id ON world_resources(item_id);
|
||||
CREATE INDEX idx_world_resources_position ON world_resources(pos_x, pos_y);
|
||||
@@ -5,13 +5,16 @@
|
||||
//! - Parsing Unity scenes with type filtering
|
||||
//! - Extracting Interactable_Resource components only
|
||||
//! - Computing world transforms
|
||||
//! - Saving resource locations to the database
|
||||
|
||||
use cursebreaker_parser::InteractableResource;
|
||||
use unity_parser::{UnityProject, TypeFilter};
|
||||
use std::path::Path;
|
||||
use unity_parser::log::DedupLogger;
|
||||
use log::{info, error, LevelFilter};
|
||||
use log::{info, error, warn, LevelFilter};
|
||||
use std::env;
|
||||
use diesel::prelude::*;
|
||||
use diesel::sqlite::SqliteConnection;
|
||||
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let logger = DedupLogger::new();
|
||||
@@ -55,21 +58,45 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
unity_parser::compute_world_transforms(&mut scene.world, &scene.entity_map);
|
||||
info!(" ✓ World transforms computed");
|
||||
|
||||
// Find all entities that have Interactable_Resource
|
||||
log::logger().flush();
|
||||
// Save resources to database
|
||||
info!("💾 Saving resources to database...");
|
||||
let database_url = env::var("DATABASE_URL").unwrap_or_else(|_| "../cursebreaker.db".to_string());
|
||||
let mut conn = SqliteConnection::establish(&database_url)?;
|
||||
|
||||
scene.world
|
||||
.query_all::<(&InteractableResource, &unity_parser::WorldTransform, &unity_parser::GameObject)>()
|
||||
.for_each(|(resource, transform, object)| {
|
||||
info!(" 📦 Resource: \"{}\"", object.name);
|
||||
info!(" • typeId: {}", resource.type_id);
|
||||
// Use diesel schema
|
||||
use cursebreaker_parser::schema::world_resources;
|
||||
|
||||
// Extract world position from WorldTransform
|
||||
let world_pos = transform.position();
|
||||
info!(" • Position: ({:.2}, {:.2}, {:.2})", world_pos.x, world_pos.y, world_pos.z);
|
||||
log::logger().flush();
|
||||
});
|
||||
// Clear the entire table (it's regenerated each run)
|
||||
diesel::delete(world_resources::table).execute(&mut conn)?;
|
||||
|
||||
let mut resource_count = 0;
|
||||
|
||||
// Insert all resources in a transaction
|
||||
conn.transaction::<_, diesel::result::Error, _>(|conn| {
|
||||
scene.world
|
||||
.query_all::<(&InteractableResource, &unity_parser::WorldTransform, &unity_parser::GameObject)>()
|
||||
.for_each(|(resource, transform, object)| {
|
||||
let world_pos = transform.position();
|
||||
|
||||
info!(" 📦 Resource: \"{}\"", object.name);
|
||||
info!(" • typeId: {}", resource.type_id);
|
||||
info!(" • Position: ({:.2}, {:.2})", world_pos.x, world_pos.z);
|
||||
|
||||
// Insert: store x and z (as y) coordinates only
|
||||
let _ = diesel::insert_into(world_resources::table)
|
||||
.values((
|
||||
world_resources::item_id.eq(resource.type_id as i32),
|
||||
world_resources::pos_x.eq(world_pos.x as f32),
|
||||
world_resources::pos_y.eq(world_pos.z as f32),
|
||||
))
|
||||
.execute(conn);
|
||||
|
||||
resource_count += 1;
|
||||
});
|
||||
Ok(())
|
||||
})?;
|
||||
|
||||
info!("✅ Saved {} resources to database", resource_count);
|
||||
log::logger().flush();
|
||||
}
|
||||
Err(e) => {
|
||||
|
||||
@@ -155,6 +155,14 @@ diesel::table! {
|
||||
}
|
||||
}
|
||||
|
||||
diesel::table! {
|
||||
world_resources (item_id, pos_x, pos_y) {
|
||||
item_id -> Integer,
|
||||
pos_x -> Float,
|
||||
pos_y -> Float,
|
||||
}
|
||||
}
|
||||
|
||||
diesel::joinable!(crafting_recipe_items -> crafting_recipes (recipe_id));
|
||||
diesel::joinable!(crafting_recipe_items -> items (item_id));
|
||||
diesel::joinable!(crafting_recipes -> items (product_item_id));
|
||||
@@ -175,4 +183,5 @@ diesel::allow_tables_to_appear_in_same_query!(
|
||||
quests,
|
||||
shops,
|
||||
traits,
|
||||
world_resources,
|
||||
);
|
||||
|
||||
@@ -15,14 +15,12 @@ use serde_yaml::Mapping;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct InteractableResource {
|
||||
pub max_health: i64,
|
||||
pub type_id: i64,
|
||||
}
|
||||
|
||||
impl UnityComponent for InteractableResource {
|
||||
fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option<Self> {
|
||||
Some(Self {
|
||||
max_health: unity_parser::yaml_helpers::get_i64(yaml, "maxHealth").unwrap_or(0),
|
||||
type_id: unity_parser::yaml_helpers::get_i64(yaml, "typeId").unwrap_or(0),
|
||||
})
|
||||
}
|
||||
|
||||
BIN
cursebreaker.db
BIN
cursebreaker.db
Binary file not shown.
Reference in New Issue
Block a user