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.db diesel migration:*)",
|
"Bash(DATABASE_URL=cursebreaker.db diesel migration:*)",
|
||||||
"Bash(DATABASE_URL=../cursebreaker-parser/cursebreaker.db cargo run:*)",
|
"Bash(DATABASE_URL=../cursebreaker-parser/cursebreaker.db cargo run:*)",
|
||||||
"Bash(identify:*)"
|
"Bash(identify:*)",
|
||||||
|
"Bash(diesel migration revert:*)"
|
||||||
],
|
],
|
||||||
"additionalDirectories": [
|
"additionalDirectories": [
|
||||||
"/home/connor/repos/CBAssets/"
|
"/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
|
//! - Parsing Unity scenes with type filtering
|
||||||
//! - Extracting Interactable_Resource components only
|
//! - Extracting Interactable_Resource components only
|
||||||
//! - Computing world transforms
|
//! - Computing world transforms
|
||||||
|
//! - Saving resource locations to the database
|
||||||
|
|
||||||
use cursebreaker_parser::InteractableResource;
|
use cursebreaker_parser::InteractableResource;
|
||||||
use unity_parser::{UnityProject, TypeFilter};
|
use unity_parser::{UnityProject, TypeFilter};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use unity_parser::log::DedupLogger;
|
use unity_parser::log::DedupLogger;
|
||||||
use log::{info, error, LevelFilter};
|
use log::{info, error, warn, LevelFilter};
|
||||||
use std::env;
|
use std::env;
|
||||||
|
use diesel::prelude::*;
|
||||||
|
use diesel::sqlite::SqliteConnection;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let logger = DedupLogger::new();
|
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);
|
unity_parser::compute_world_transforms(&mut scene.world, &scene.entity_map);
|
||||||
info!(" ✓ World transforms computed");
|
info!(" ✓ World transforms computed");
|
||||||
|
|
||||||
// Find all entities that have Interactable_Resource
|
// Save resources to database
|
||||||
log::logger().flush();
|
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
|
// Use diesel schema
|
||||||
.query_all::<(&InteractableResource, &unity_parser::WorldTransform, &unity_parser::GameObject)>()
|
use cursebreaker_parser::schema::world_resources;
|
||||||
.for_each(|(resource, transform, object)| {
|
|
||||||
info!(" 📦 Resource: \"{}\"", object.name);
|
|
||||||
info!(" • typeId: {}", resource.type_id);
|
|
||||||
|
|
||||||
// Extract world position from WorldTransform
|
// Clear the entire table (it's regenerated each run)
|
||||||
let world_pos = transform.position();
|
diesel::delete(world_resources::table).execute(&mut conn)?;
|
||||||
info!(" • Position: ({:.2}, {:.2}, {:.2})", world_pos.x, world_pos.y, world_pos.z);
|
|
||||||
log::logger().flush();
|
|
||||||
});
|
|
||||||
|
|
||||||
|
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();
|
log::logger().flush();
|
||||||
}
|
}
|
||||||
Err(e) => {
|
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 -> crafting_recipes (recipe_id));
|
||||||
diesel::joinable!(crafting_recipe_items -> items (item_id));
|
diesel::joinable!(crafting_recipe_items -> items (item_id));
|
||||||
diesel::joinable!(crafting_recipes -> items (product_item_id));
|
diesel::joinable!(crafting_recipes -> items (product_item_id));
|
||||||
@@ -175,4 +183,5 @@ diesel::allow_tables_to_appear_in_same_query!(
|
|||||||
quests,
|
quests,
|
||||||
shops,
|
shops,
|
||||||
traits,
|
traits,
|
||||||
|
world_resources,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -15,14 +15,12 @@ use serde_yaml::Mapping;
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct InteractableResource {
|
pub struct InteractableResource {
|
||||||
pub max_health: i64,
|
|
||||||
pub type_id: i64,
|
pub type_id: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UnityComponent for InteractableResource {
|
impl UnityComponent for InteractableResource {
|
||||||
fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option<Self> {
|
fn parse(yaml: &Mapping, _ctx: &ComponentContext) -> Option<Self> {
|
||||||
Some(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),
|
type_id: unity_parser::yaml_helpers::get_i64(yaml, "typeId").unwrap_or(0),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user