read_wire_ports/
read_wire_ports.rs

1use brdb::{AsBrdbValue, Brdb, IntoReader, WireChunkSoA, schema::BrdbStruct};
2use std::{
3    collections::{HashMap, HashSet},
4    fmt::Write,
5    path::PathBuf,
6};
7struct ComponentMeta {
8    wire_inputs: HashSet<u16>,
9    wire_outputs: HashSet<u16>,
10}
11
12struct BrickMeta {
13    type_index: u32,
14    components: Vec<(u16, BrdbStruct)>,
15}
16
17/// Reads a world and prints out some of its information
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19    let path = PathBuf::from("./world.brdb");
20
21    let db = Brdb::open(path)?.into_reader();
22
23    let data = db.global_data()?;
24    let component_schema = db.components_schema()?;
25
26    let chunks = db.brick_chunk_index(1)?;
27
28    // Track seen brick types
29    let mut brick_type_set = HashSet::new();
30
31    // Track seen component types to map to their wire ports
32    let mut component_map = HashMap::new();
33
34    // Track brick -> component mappings
35    let mut brick_map = HashMap::new();
36
37    for chunk in &chunks {
38        let soa = db.brick_chunk_soa(1, chunk.index)?;
39
40        // Iterate basic bricks
41        let pb_index = soa.procedural_brick_starting_index;
42        for (i, t) in soa.brick_type_indices.into_iter().enumerate() {
43            if t >= pb_index {
44                continue;
45            }
46            if brick_type_set.contains(&t) {
47                continue;
48            }
49            brick_type_set.insert(t);
50
51            // Insert bricks of unique types
52            brick_map.insert(
53                (chunk.index, i),
54                BrickMeta {
55                    type_index: t,
56                    components: Vec::new(),
57                },
58            );
59        }
60
61        if chunk.num_components > 0 {
62            let (soa, components) = db.component_chunk_soa(1, chunk.index)?;
63            let indices = soa.component_brick_indices;
64
65            // Expand the type index/num instances into a flat list of type indices
66            let type_indices = soa
67                .component_type_counters
68                .iter()
69                .flat_map(|v| {
70                    let index = v.type_index as u16;
71                    (0..v.num_instances).map(move |_| index)
72                })
73                .collect::<Vec<_>>();
74
75            // Add each component and its type to the brick map
76            for (i, c) in components.iter().enumerate() {
77                let brick_index = indices[i as usize].as_brdb_u32()?;
78                let type_index = type_indices[i as usize];
79                if let Some(brick) = brick_map.get_mut(&(chunk.index, brick_index as usize)) {
80                    brick.components.push((type_index, c.clone()));
81                } else {
82                    continue;
83                }
84
85                // Register the component type if not already registered
86                if !component_map.contains_key(&type_index) {
87                    component_map.insert(
88                        type_index,
89                        ComponentMeta {
90                            wire_inputs: HashSet::new(),
91                            wire_outputs: HashSet::new(),
92                        },
93                    );
94                }
95            }
96        }
97    }
98
99    // Add the wire ports to the component map
100    for chunk in &chunks {
101        if chunk.num_wires > 0 {
102            let soa = db.wire_chunk_soa(1, chunk.index)?.to_value();
103            let soa: WireChunkSoA = (&soa).try_into()?;
104            for port in soa.local_wire_sources {
105                if let Some(meta) = component_map.get_mut(&port.component_type_index) {
106                    meta.wire_outputs.insert(port.port_index);
107                }
108            }
109            for port in soa.local_wire_targets {
110                if let Some(meta) = component_map.get_mut(&port.component_type_index) {
111                    meta.wire_inputs.insert(port.port_index);
112                }
113            }
114            for port in soa.remote_wire_sources {
115                if let Some(meta) = component_map.get_mut(&port.component_type_index) {
116                    meta.wire_outputs.insert(port.port_index);
117                }
118            }
119            for port in soa.remote_wire_targets {
120                if let Some(meta) = component_map.get_mut(&port.component_type_index) {
121                    meta.wire_inputs.insert(port.port_index);
122                }
123            }
124        }
125    }
126
127    // Print the brick -> component mappings
128    for meta in brick_map.values() {
129        let brick_type_str = data.basic_brick_asset_names[meta.type_index as usize].clone();
130        for c in &meta.components {
131            let component_type_str = data.component_type_names[c.0 as usize].clone();
132            let c_entry = component_map.get(&c.0).unwrap();
133            let wire_inputs = c_entry
134                .wire_inputs
135                .iter()
136                .map(|i| {
137                    format!(
138                        "  {}",
139                        data.component_wire_port_names[*i as usize].to_owned()
140                    )
141                })
142                .collect::<Vec<_>>()
143                .join("\n");
144            let wire_outputs = c_entry
145                .wire_outputs
146                .iter()
147                .map(|i| {
148                    format!(
149                        "  {}",
150                        data.component_wire_port_names[*i as usize].to_owned()
151                    )
152                })
153                .collect::<Vec<_>>()
154                .join("\n");
155
156            let mut component_struct = String::new();
157            for (name, properties) in &component_schema.structs {
158                if name != &c.1.name {
159                    continue;
160                }
161
162                let name = component_schema
163                    .intern
164                    .lookup(*name)
165                    .unwrap_or("UnknownStruct".to_owned());
166                writeln!(component_struct, "struct {name} {{")?;
167                for (prop_name, prop_type) in properties {
168                    let prop_name = component_schema
169                        .intern
170                        .lookup(*prop_name)
171                        .unwrap_or("UnknownProperty".to_owned());
172                    writeln!(
173                        component_struct,
174                        "    {prop_name}: {},",
175                        prop_type.as_string(&component_schema)
176                    )?;
177                }
178                writeln!(component_struct, "}}")?;
179            }
180
181            println!(
182                "Brick: {}\nComponent: {}\n{}Inputs:\n{}\nOutputs:\n{}\n\n",
183                brick_type_str, component_type_str, component_struct, wire_inputs, wire_outputs
184            );
185        }
186    }
187
188    Ok(())
189}