use assembly_fdb::mem::{Database, Row, Table, Tables}; use color_eyre::eyre::{eyre, WrapErr}; use mapr::Mmap; use std::{ collections::{BTreeMap, BTreeSet}, fs::File, path::PathBuf, }; use structopt::StructOpt; #[derive(StructOpt)] struct Options { fdb: PathBuf, } fn get_table<'a>(tables: Tables<'a>, name: &str) -> color_eyre::Result> { let table = tables .by_name(name) .ok_or_else(|| eyre!("Missing table '{}'", name))??; Ok(table) } fn get_column_index(table: Table<'_>, name: &str) -> color_eyre::Result { let index = table .column_iter() .position(|col| col.name() == name) .ok_or_else(|| eyre!("Missing columns '{}'.'{}'", table.name(), name))?; Ok(index) } struct RebuildComponent<'a> { inner: Row<'a>, } impl<'a> RebuildComponent<'a> { fn activity_id(&self) -> Option { self.inner.field_at(7).unwrap().into_opt_integer() } fn id(&self) -> i32 { self.inner.field_at(0).unwrap().into_opt_integer().unwrap() } } fn main() -> color_eyre::Result<()> { color_eyre::install()?; let opts = Options::from_args(); // Load the database file let file = File::open(&opts.fdb) .wrap_err_with(|| format!("Failed to open input file '{}'", opts.fdb.display()))?; let mmap = unsafe { Mmap::map(&file)? }; let buffer: &[u8] = &mmap; // Start using the database let db = Database::new(buffer); // Find table let tables = db.tables()?; let destructible_component_table = get_table(tables, "RebuildComponent")?; assert_eq!( 7, get_column_index(destructible_component_table, "activityID")? ); let mut map: BTreeMap> = BTreeMap::new(); for inner in destructible_component_table.row_iter() { let component = RebuildComponent { inner }; let id = component.id(); if let Some(faction) = component.activity_id() { if faction > -1 { map.entry(faction).or_default().insert(id); } } } let string = serde_json::to_string(&map)?; println!("{}", string); Ok(()) }