Skip to main content

BrReader

Struct BrReader 

Source
pub struct BrReader<T> { /* private fields */ }

Implementations§

Source§

impl<T> BrReader<T>

Source

pub fn new(brdb: T) -> Self
where T: BrFsReader,

Source

pub fn to_pending(&self) -> Result<BrPendingFs, BrFsError>
where T: BrFsReader,

Convert this filesystem to a pending filesystem with all files present

Examples found in repository?
examples/world_replace_owner.rs (line 49)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    let src = PathBuf::from("world.brdb");
9    let dst = PathBuf::from("world_patched.brz");
10
11    assert!(src.exists());
12
13    let db = Brdb::open(src)?.into_reader();
14
15    let owners = db.owners_soa()?;
16
17    // Parse the owners from BrdbValues
18    let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
19
20    // Modify the owner ids
21    new_soa
22        .display_names
23        .iter_mut()
24        .for_each(|id| *id = "PUBLIC".to_owned());
25    new_soa
26        .user_names
27        .iter_mut()
28        .for_each(|id| *id = "PUBLIC".to_owned());
29    new_soa
30        .user_ids
31        .iter_mut()
32        .for_each(|id| *id = Guid::default());
33
34    // convert the owners struct of arrays into bytes using the owners schema
35    let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
36
37    let patch = BrPendingFs::Root(vec![(
38        "World".to_owned(),
39        BrPendingFs::Folder(Some(vec![(
40            "0".to_string(),
41            BrPendingFs::Folder(Some(vec![(
42                "Owners.mps".to_string(),
43                BrPendingFs::File(Some(content)),
44            )])),
45        )])),
46    )]);
47
48    // use .to_pending_patch() if you want to update the same world
49    let pending = db.to_pending()?.with_patch(patch)?;
50    if dst.exists() {
51        std::fs::remove_file(&dst)?;
52    }
53    Brz::write_pending(&dst, pending)?;
54
55    println!("{}", Brz::open(&dst)?.into_reader().owners_soa()?);
56
57    Ok(())
58}
More examples
Hide additional examples
examples/world_move_bricks.rs (line 39)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    println!("Warning - This code will break if the brick chunk struct changes!!");
10
11    let db = Brdb::open(path)?.into_reader();
12
13    let data = db.global_data()?;
14    let mut grid = UnsavedGrid::default();
15
16    let mut total_bricks = 0;
17    for chunk in db.brick_chunk_index(1)? {
18        for brick in db
19            .brick_chunk_soa(1, chunk.index)?
20            .iter_bricks(chunk.index, data.clone())
21        {
22            // If we wanted wires/components, we'd need to track the bricks here by their chunk index and brick index
23            total_bricks += 1;
24
25            let mut brick = brick?;
26            brick.position += Position::new(3000, 0, 0);
27            grid.add_brick(data.as_ref(), &brick);
28        }
29
30        if chunk.num_components > 0 {
31            println!("sorry, this example doesn't handle components");
32        }
33        if chunk.num_wires > 0 {
34            println!("sorry, this example doesn't handle wires");
35        }
36    }
37    println!("{total_bricks} bricks");
38
39    let mut pending = db.to_pending()?;
40
41    // Replace the main grid (1) with the grid we created
42    *pending.cd_mut("World/0/Bricks/Grids/1")? = grid.to_pending(
43        data.proc_brick_starting_index(),
44        db.components_schema()?.as_ref(),
45    )?;
46
47    if dst.exists() {
48        std::fs::remove_file(&dst)?;
49    }
50    Brdb::new(&dst)?.write_pending("Move the bricks", pending)?;
51
52    // Verify bricks can be read
53    let db = Brdb::open(dst)?.into_reader();
54    for chunk in db.brick_chunk_index(1)? {
55        let _ = db.brick_chunk_soa(1, chunk.index)?;
56    }
57
58    Ok(())
59}
examples/world_freeze_entities.rs (line 51)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let chunks = db.entity_chunk_index()?;
14    let entity_schema = db.entities_schema()?;
15    let global_data = db.global_data()?;
16    let mut chunk_files = vec![];
17
18    for index in chunks {
19        // Entity_chunk loads entities and their entity data
20        let entities = db.entity_chunk(index)?;
21
22        // Re-assemble the soa. using add_entity ensures the extra data is correctly handled
23        let mut soa = EntityChunkSoA::default();
24        for mut e in entities.into_iter() {
25            e.frozen = true;
26            soa.add_entity(&global_data, &e, e.id.unwrap() as u32);
27        }
28
29        chunk_files.push((
30            format!("{index}.mps"),
31            // EntityChunkSoA::to_bytes ensures the extra data is written after the SoA data
32            BrPendingFs::File(Some(soa.to_bytes(&entity_schema)?)),
33        ));
34    }
35
36    let patch = BrPendingFs::Root(vec![(
37        "World".to_owned(),
38        BrPendingFs::Folder(Some(vec![(
39            "0".to_string(),
40            BrPendingFs::Folder(Some(vec![(
41                "Entities".to_string(),
42                BrPendingFs::Folder(Some(vec![(
43                    "Chunks".to_string(),
44                    BrPendingFs::Folder(Some(chunk_files)),
45                )])),
46            )])),
47        )])),
48    )]);
49
50    // Use .to_pending_patch() if you want to update the same world
51    let pending = db.to_pending()?.with_patch(patch)?;
52    if dst.exists() {
53        std::fs::remove_file(&dst)?;
54    }
55    Brdb::new(&dst)?.write_pending("Freeze Entities", pending)?;
56
57    // Ensure entities can be read
58    let db = Brdb::open(dst)?.into_reader();
59    let chunks = db.entity_chunk_index()?;
60    for index in chunks {
61        let _ = db.entity_chunk(index)?;
62    }
63
64    Ok(())
65}
examples/world_remove_shadows.rs (line 112)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let mut grid_ids = vec![1];
14
15    // Iterate all entity chunks to find dynamic brick grids...
16    // This could totally be a helper function
17    for index in db.entity_chunk_index()? {
18        for e in db.entity_chunk(index)? {
19            // Ensure the chunk is a dynamic brick grid
20            if !e.is_brick_grid() {
21                continue;
22            }
23            let Some(id) = e.id else {
24                continue;
25            };
26            grid_ids.push(id);
27        }
28    }
29
30    let component_schema = db.components_schema()?;
31    let mut grids_files = vec![];
32
33    // Iterate all grids (there can be bricks on entities)
34    for grid in &grid_ids {
35        let chunks = db.brick_chunk_index(*grid)?;
36        let mut chunk_files = vec![];
37        let mut num_grid_modified = 0;
38
39        // Iterate all chunks in the grid
40        for index in chunks {
41            let mut num_chunk_modified = 0;
42            if index.num_components == 0 {
43                println!("ignoring grid {grid} chunk {} with no components", *index);
44                continue;
45            }
46
47            // Iterate all the components in the chunk
48            let (mut soa, components) = db.component_chunk(*grid, *index)?;
49            for mut s in components {
50                // Disable the shadow casting property if it's present and true
51                if s.prop("bCastShadows")
52                    .is_ok_and(|v| v.as_brdb_bool().unwrap_or_default())
53                {
54                    println!(
55                        "grid {grid} chunk {} mutating component {}",
56                        *index,
57                        s.get_name()
58                    );
59                    s.set_prop("bCastShadows", BrdbValue::Bool(false))?;
60                    num_grid_modified += 1;
61                    num_chunk_modified += 1;
62                }
63
64                soa.unwritten_struct_data.push(Box::new(s));
65            }
66
67            if num_chunk_modified == 0 {
68                continue;
69            }
70
71            chunk_files.push((
72                format!("{}.mps", *index),
73                // ComponentChunkSoA::to_bytes ensures the extra data is written after the SoA data
74                BrPendingFs::File(Some(soa.to_bytes(&component_schema)?)),
75            ));
76        }
77
78        if num_grid_modified == 0 {
79            println!("grid {grid} has no shadow-casting components, skipping");
80            continue;
81        } else {
82            println!(
83                "grid {grid} has {num_grid_modified} shadow-casting components in {} files",
84                chunk_files.len()
85            );
86        }
87
88        grids_files.push((
89            grid.to_string(),
90            BrPendingFs::Folder(Some(vec![(
91                "Components".to_string(),
92                BrPendingFs::Folder(Some(chunk_files)),
93            )])),
94        ))
95    }
96
97    let patch = BrPendingFs::Root(vec![(
98        "World".to_owned(),
99        BrPendingFs::Folder(Some(vec![(
100            "0".to_string(),
101            BrPendingFs::Folder(Some(vec![(
102                "Bricks".to_string(),
103                BrPendingFs::Folder(Some(vec![(
104                    "Grids".to_string(),
105                    BrPendingFs::Folder(Some(grids_files)),
106                )])),
107            )])),
108        )])),
109    )]);
110
111    // Use .to_pending_patch() if you want to update the same world
112    let pending = db.to_pending()?.with_patch(patch)?;
113    if dst.exists() {
114        std::fs::remove_file(&dst)?;
115    }
116    Brdb::new(&dst)?.write_pending("Disable Shadow Casting", pending)?;
117
118    // Ensure all the components can be read
119    let db = Brdb::open(dst)?.into_reader();
120    for grid in grid_ids {
121        let chunks = db.brick_chunk_index(grid)?;
122        for index in chunks {
123            if index.num_components == 0 {
124                continue;
125            }
126            let (_soa, _components) = db.component_chunk(grid, *index)?;
127        }
128    }
129
130    Ok(())
131}
Source

pub fn to_pending_patch(&self) -> Result<BrPendingFs, BrFsError>
where T: BrFsReader,

Convert this filesystem to a pending filesystem all files in Patch mode (None for unchanged)

Examples found in repository?
examples/world_replace_bundle.rs (line 32)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    let meta_dst = PathBuf::from("dst.brdb");
8    let meta_src = PathBuf::from("src.brdb");
9
10    let src_f = Brdb::open(meta_src)?.into_reader();
11    let dst_f = Brdb::open(meta_dst)?.into_reader();
12
13    println!(
14        "replacing: {}",
15        String::from_utf8(dst_f.read_file("Meta/Bundle.json")?).unwrap()
16    );
17    println!(
18        "with: {}",
19        String::from_utf8(src_f.read_file("Meta/Bundle.json")?).unwrap()
20    );
21
22    let patch = BrPendingFs::Root(vec![(
23        "Meta".to_owned(),
24        BrPendingFs::Folder(Some(vec![(
25            "Bundle.json".to_string(),
26            BrPendingFs::File(Some(src_f.read_file("Meta/Bundle.json")?)),
27        )])),
28    )]);
29
30    dst_f.write_pending(
31        "Replace Bundle",
32        dst_f.to_pending_patch()?.with_patch(patch)?,
33    )?;
34
35    Ok(())
36}
More examples
Hide additional examples
examples/world_owner_tool.rs (line 176)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    let mut args = std::env::args().into_iter().peekable();
8    let cmd = args.next().unwrap();
9    if !args.peek().is_some() {
10        println!("usage: {cmd} show world.brdb");
11        println!("usage: {cmd} apply world.brdb owners.csv");
12        println!(
13            "owners.csv must be `display_name,user_name,user_id,old_user_id` where old_user_id is the one to replace."
14        );
15        process::exit(0);
16    }
17
18    let command = args.next().unwrap();
19    if command != "show" && command != "apply" {
20        eprintln!("unknown command. expected `show` or `apply`");
21        process::exit(1);
22    }
23
24    let Some(file) = args.next() else {
25        eprintln!("missing world file arg");
26        process::exit(1);
27    };
28
29    let dst = PathBuf::from(&file);
30    if !dst.exists() {
31        eprintln!("file {file} does not exist");
32        process::exit(1);
33    }
34
35    let db = Brdb::open(dst)?.into_reader();
36
37    let owners = db.owners_soa()?;
38
39    if command == "show" {
40        if args.peek().is_some() {
41            eprintln!("too many arguments!");
42            process::exit(1);
43        }
44
45        let owners_csv = owners
46            .prop("DisplayNames")?
47            .as_array()?
48            .iter()
49            .zip(owners.prop("UserNames")?.as_array()?.iter())
50            .zip(owners.prop("UserIds")?.as_array()?.iter())
51            .map(|((display_name, user_name), user_id)| {
52                format!(
53                    "{},{},{}",
54                    display_name.as_str().unwrap(),
55                    user_name.as_str().unwrap(),
56                    Guid::try_from(user_id).unwrap().uuid(),
57                )
58            })
59            .collect::<Vec<_>>();
60        println!("display_name,user_name,user_id\n{}", owners_csv.join("\n"));
61    } else if command == "apply" {
62        let Some(apply_file) = args.next() else {
63            eprintln!("missing owners csv file arg");
64            process::exit(1);
65        };
66        if args.peek().is_some() {
67            eprintln!("too many arguments!");
68            process::exit(1);
69        }
70
71        let apply_path = PathBuf::from(&apply_file);
72        if !apply_path.exists() {
73            eprintln!("file {apply_file} does not exist");
74            process::exit(1);
75        }
76
77        let mut display_name_index = None;
78        let mut user_name_index = None;
79        let mut user_id_index = None;
80        let mut old_user_id_index = None;
81        let mut apply_data = String::new();
82        File::open(apply_path)?.read_to_string(&mut apply_data)?;
83        let Some((header, rows)) = apply_data.split_once("\n") else {
84            eprintln!("file {apply_file} does not have any rows");
85            process::exit(1);
86        };
87        for (i, key) in header.split(",").enumerate() {
88            match key.trim().to_ascii_lowercase().as_ref() {
89                "display_name" => {
90                    display_name_index = Some(i);
91                }
92                "user_name" => {
93                    user_name_index = Some(i);
94                }
95                "user_id" => {
96                    user_id_index = Some(i);
97                }
98                "old_user_id" => old_user_id_index = Some(i),
99                other => {
100                    eprintln!("unknown column {other} in {apply_file}");
101                    process::exit(1);
102                }
103            }
104        }
105
106        let missing = [
107            ("display_name", display_name_index.is_none()),
108            ("user_name", user_name_index.is_none()),
109            ("user_id", user_id_index.is_none()),
110            ("old_user_id", old_user_id_index.is_none()),
111        ]
112        .into_iter()
113        .filter_map(|(k, cond)| cond.then_some(k.to_owned()))
114        .collect::<Vec<_>>();
115        if !missing.is_empty() {
116            eprintln!("missing columns: {}", missing.join(","));
117            process::exit(1);
118        }
119
120        let display_name_index = display_name_index.unwrap();
121        let user_name_index = user_name_index.unwrap();
122        let user_id_index = user_id_index.unwrap();
123        let old_user_id_index = old_user_id_index.unwrap();
124
125        // Parse the owners from BrdbValues
126        let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
127        let owners_lut = rows
128            .trim()
129            .split("\n")
130            .map(|r| r.trim().split(",").collect::<Vec<&str>>())
131            .map(|cols| {
132                let user_name = cols[user_name_index];
133                let display_name = cols[display_name_index];
134                let user_id = Uuid::parse_str(&cols[user_id_index])
135                    .expect(&format!("invalid uuid: {}", cols[user_id_index]));
136                let old_user_id = Uuid::parse_str(&cols[old_user_id_index])
137                    .expect(&format!("invalid old uuid: {}", cols[old_user_id_index]));
138                (old_user_id, (user_name, display_name, user_id))
139            })
140            .collect::<HashMap<_, _>>();
141        println!("{owners_lut:?}");
142
143        let mut changes = 0;
144
145        for i in 0..new_soa.user_ids.len() {
146            let old_id = new_soa.user_ids[i].uuid();
147            let Some((user_name, display_name, user_id)) = owners_lut.get(&old_id) else {
148                println!("missing old id for {old_id} - ignoring");
149                continue;
150            };
151            println!("replacing {old_id} with {user_id} - {user_name} ({display_name})");
152            new_soa.user_names[i] = (*user_name).to_owned();
153            new_soa.display_names[i] = (*display_name).to_owned();
154            new_soa.user_ids[i] = Guid::from_uuid((*user_id).clone());
155            changes += 1;
156        }
157
158        if changes == 0 {
159            println!("world left unchanged");
160            std::process::exit(0);
161        }
162
163        // convert the owners struct of arrays into bytes using the owners schema
164        let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
165
166        let patch = BrPendingFs::Root(vec![(
167            "World".to_owned(),
168            BrPendingFs::Folder(Some(vec![(
169                "0".to_string(),
170                BrPendingFs::Folder(Some(vec![(
171                    "Owners.mps".to_string(),
172                    BrPendingFs::File(Some(content)),
173                )])),
174            )])),
175        )]);
176        db.write_pending("Replace owners", db.to_pending_patch()?.with_patch(patch)?)?;
177        println!("revision created")
178    }
179
180    Ok(())
181}
Source

pub fn bundle_json(&self) -> Result<BundleJson, BrError>
where T: BrFsReader,

Parse Meta/Bundle.json (present in every bundle).

Source

pub fn world_json(&self) -> Result<Option<WorldJson>, BrError>
where T: BrFsReader,

Parse Meta/World.json; None for prefab bundles.

Source

pub fn prefab_json(&self) -> Result<Option<PrefabJson>, BrError>
where T: BrFsReader,

Parse Meta/Prefab.json; None for world bundles.

Source

pub fn thumbnail(&self) -> Result<Option<Vec<u8>>, BrError>
where T: BrFsReader,

Meta/Thumbnail.png bytes, when present.

Source

pub fn screenshot(&self) -> Result<Option<Vec<u8>>, BrError>
where T: BrFsReader,

Meta/Screenshot.jpg bytes, when present.

Source

pub fn world_meta(&self) -> Result<WorldMeta, BrError>
where T: BrFsReader,

Assemble the same crate::wrapper::WorldMeta the wrapper writes: bundle, world/prefab JSON, screenshot and thumbnail.

Source

pub fn prefab_paths(&self) -> Result<Vec<String>, BrError>
where T: BrFsReader,

Root-relative paths of every embedded prefab (files under Prefabs/), e.g. Prefabs/Uploads/<HASH>.brz. Empty when the bundle embeds none. These are the exact strings Prefab component properties (bundle_path_ref) reference.

Examples found in repository?
examples/write_prefab_spawner.rs (line 86)
10fn main() -> Result<(), Box<dyn std::error::Error>> {
11    // 1. Build the prefab that gets spawned: a single red brick.
12    let mut prefab = World::new();
13    prefab.meta.bundle.name = "Spawned Brick".to_string();
14    prefab.bricks.push(Brick {
15        position: (0, 0, 6).into(),
16        color: (255, 0, 0).into(),
17        ..Default::default()
18    });
19    prefab.make_prefab();
20    let prefab_bytes = prefab.to_brz_vec()?;
21
22    // 2. Build the outer world holding the button + spawner.
23    let mut world = World::new();
24    // Registers the built-in component/port tables so the Button and
25    // PrefabSpawner component types and their wire ports resolve.
26    world.register_all_components();
27    world.meta.bundle.description = "Button-triggered prefab spawner".to_string();
28
29    // Embed the prefab; the returned path is what the spawner references.
30    let prefab_path = world.add_prefab(prefab_bytes);
31
32    // A pressable button (Component_Button on a 1x1 flat round brick). The
33    // crate exposes brick assets as constants; components it doesn't model as
34    // typed gates (like the button and spawner) are built from string names
35    // via LiteralComponent.
36    let (button, button_id) = Brick {
37        position: (0, 0, 2).into(),
38        color: (0, 255, 0).into(),
39        asset: assets::bricks::B_1X1F_ROUND,
40        ..Default::default()
41    }
42    .with_component(assets::LiteralComponent::new("Component_Button").with_data([(
43        "PromptCustomLabel",
44        Box::new("Spawn Brick".to_string()) as Box<dyn AsBrdbValue>,
45    )]))
46    .with_id_split();
47
48    // The prefab-spawner gate, pointed at the embedded prefab.
49    let (spawner, spawner_id) = Brick {
50        position: (15, 0, 1).into(),
51        color: (0, 0, 255).into(),
52        asset: assets::bricks::B_1X1_GATE_EXEC_PREFAB_SPAWNER,
53        ..Default::default()
54    }
55    .with_component(
56        assets::LiteralComponent::new("BrickComponentType_WireGraph_Exec_PrefabSpawner").with_data(
57            [(
58                "Prefab",
59                Box::new(prefab_path.clone()) as Box<dyn AsBrdbValue>,
60            )],
61        ),
62    )
63    .with_id_split();
64
65    world.add_bricks([button, spawner]);
66
67    // Wire the button's held signal into the spawner's Exec input, so a
68    // press fires the spawn.
69    world.add_wire_connection(
70        WirePort::new(button_id, "Component_Button", "bHeld"),
71        WirePort::new(
72            spawner_id,
73            "BrickComponentType_WireGraph_Exec_PrefabSpawner",
74            "Exec",
75        ),
76    );
77
78    // 3. Write it out.
79    let path = PathBuf::from("./example_prefab_spawner.brz");
80    world.write_brz(&path)?;
81    println!("wrote {}", path.display());
82
83    // Read it back to confirm the embedded prefab and wire survived.
84    let reader = Brz::open(&path)?.into_reader();
85    println!("embedded prefab: {}", prefab_path);
86    println!("prefab paths in archive: {:?}", reader.prefab_paths()?);
87    println!("{}", reader.get_fs()?.render());
88
89    Ok(())
90}
Source

pub fn read_prefabs(&self) -> Result<IndexMap<String, Vec<u8>>, BrError>
where T: BrFsReader,

Read every embedded prefab: root-relative path → raw .brz bytes. The result is directly assignable to World::prefabs.

Source

pub fn open_prefab(&self, path: &str) -> Result<Brz, BrError>
where T: BrFsReader,

Parse an embedded prefab archive (a path from Self::prefab_paths or a component’s Prefab property). Chain .into_reader() to read inside.

Source

pub fn read_global_data(&self) -> Result<Arc<BrdbSchemaGlobalData>, BrError>
where T: BrFsReader,

Read the GlobalData

Source

pub fn global_data(&self) -> Result<Arc<BrdbSchemaGlobalData>, BrError>
where T: BrFsReader,

Read and cache the GlobalData

Examples found in repository?
examples/dump_assets.rs (line 7)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let p = PathBuf::from(std::env::args().nth(1).unwrap());
6    let db = Brdb::open(&p)?.into_reader();
7    let gd = db.global_data()?;
8    let mut by_type: BTreeMap<String, Vec<String>> = BTreeMap::new();
9    for (ty, name) in &gd.external_asset_references {
10        by_type.entry(ty.clone()).or_default().push(name.clone());
11    }
12    println!("=== external_asset_references: {} total, {} types ===",
13        gd.external_asset_references.len(), by_type.len());
14    for (ty, names) in &by_type {
15        println!("\n[{}] ({})", ty, names.len());
16        for n in names { println!("  {}", n); }
17    }
18    println!("\n=== external_asset_types ===");
19    let mut ts: Vec<_> = gd.external_asset_types.iter().collect();
20    ts.sort();
21    for t in ts { println!("  {}", t); }
22    Ok(())
23}
More examples
Hide additional examples
examples/read_brz.rs (line 11)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
examples/read_components.rs (line 7)
4fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
5    println!(
6        "Component types: {:?}",
7        db.global_data()?.component_type_names
8    );
9    println!(
10        "Component structs: {:?}",
11        db.global_data()?.component_data_struct_names
12    );
13    // Probe grid ids 1.. until one is missing (covers the main grid plus any
14    // microchip inner grids, which entity discovery may not surface).
15    for gid in 1..32 {
16        let chunks = match db.brick_chunk_index(gid) {
17            Ok(c) => c,
18            Err(_) => break,
19        };
20        println!("=== grid {gid} ===");
21        for chunk in chunks {
22            println!(
23                "chunk {} bricks={} components={} wires={}",
24                chunk.index, chunk.num_bricks, chunk.num_components, chunk.num_wires
25            );
26            if chunk.num_components > 0 {
27                match db.component_chunk_soa(gid, chunk.index) {
28                    Ok((_soa, components)) => {
29                        for c in components {
30                            println!("  component: {c}");
31                        }
32                    }
33                    Err(e) => {
34                        println!("  ERROR reading components: {e}");
35                        return Err(e.into());
36                    }
37                }
38            }
39        }
40    }
41    Ok(())
42}
examples/world_move_bricks.rs (line 13)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    println!("Warning - This code will break if the brick chunk struct changes!!");
10
11    let db = Brdb::open(path)?.into_reader();
12
13    let data = db.global_data()?;
14    let mut grid = UnsavedGrid::default();
15
16    let mut total_bricks = 0;
17    for chunk in db.brick_chunk_index(1)? {
18        for brick in db
19            .brick_chunk_soa(1, chunk.index)?
20            .iter_bricks(chunk.index, data.clone())
21        {
22            // If we wanted wires/components, we'd need to track the bricks here by their chunk index and brick index
23            total_bricks += 1;
24
25            let mut brick = brick?;
26            brick.position += Position::new(3000, 0, 0);
27            grid.add_brick(data.as_ref(), &brick);
28        }
29
30        if chunk.num_components > 0 {
31            println!("sorry, this example doesn't handle components");
32        }
33        if chunk.num_wires > 0 {
34            println!("sorry, this example doesn't handle wires");
35        }
36    }
37    println!("{total_bricks} bricks");
38
39    let mut pending = db.to_pending()?;
40
41    // Replace the main grid (1) with the grid we created
42    *pending.cd_mut("World/0/Bricks/Grids/1")? = grid.to_pending(
43        data.proc_brick_starting_index(),
44        db.components_schema()?.as_ref(),
45    )?;
46
47    if dst.exists() {
48        std::fs::remove_file(&dst)?;
49    }
50    Brdb::new(&dst)?.write_pending("Move the bricks", pending)?;
51
52    // Verify bricks can be read
53    let db = Brdb::open(dst)?.into_reader();
54    for chunk in db.brick_chunk_index(1)? {
55        let _ = db.brick_chunk_soa(1, chunk.index)?;
56    }
57
58    Ok(())
59}
examples/world_freeze_entities.rs (line 15)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let chunks = db.entity_chunk_index()?;
14    let entity_schema = db.entities_schema()?;
15    let global_data = db.global_data()?;
16    let mut chunk_files = vec![];
17
18    for index in chunks {
19        // Entity_chunk loads entities and their entity data
20        let entities = db.entity_chunk(index)?;
21
22        // Re-assemble the soa. using add_entity ensures the extra data is correctly handled
23        let mut soa = EntityChunkSoA::default();
24        for mut e in entities.into_iter() {
25            e.frozen = true;
26            soa.add_entity(&global_data, &e, e.id.unwrap() as u32);
27        }
28
29        chunk_files.push((
30            format!("{index}.mps"),
31            // EntityChunkSoA::to_bytes ensures the extra data is written after the SoA data
32            BrPendingFs::File(Some(soa.to_bytes(&entity_schema)?)),
33        ));
34    }
35
36    let patch = BrPendingFs::Root(vec![(
37        "World".to_owned(),
38        BrPendingFs::Folder(Some(vec![(
39            "0".to_string(),
40            BrPendingFs::Folder(Some(vec![(
41                "Entities".to_string(),
42                BrPendingFs::Folder(Some(vec![(
43                    "Chunks".to_string(),
44                    BrPendingFs::Folder(Some(chunk_files)),
45                )])),
46            )])),
47        )])),
48    )]);
49
50    // Use .to_pending_patch() if you want to update the same world
51    let pending = db.to_pending()?.with_patch(patch)?;
52    if dst.exists() {
53        std::fs::remove_file(&dst)?;
54    }
55    Brdb::new(&dst)?.write_pending("Freeze Entities", pending)?;
56
57    // Ensure entities can be read
58    let db = Brdb::open(dst)?.into_reader();
59    let chunks = db.entity_chunk_index()?;
60    for index in chunks {
61        let _ = db.entity_chunk(index)?;
62    }
63
64    Ok(())
65}
examples/read_world.rs (line 18)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
Source

pub fn owners_soa(&self) -> Result<BrdbStruct, BrError>
where T: BrFsReader,

Read the Owners table

Examples found in repository?
examples/world_replace_owner.rs (line 15)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    let src = PathBuf::from("world.brdb");
9    let dst = PathBuf::from("world_patched.brz");
10
11    assert!(src.exists());
12
13    let db = Brdb::open(src)?.into_reader();
14
15    let owners = db.owners_soa()?;
16
17    // Parse the owners from BrdbValues
18    let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
19
20    // Modify the owner ids
21    new_soa
22        .display_names
23        .iter_mut()
24        .for_each(|id| *id = "PUBLIC".to_owned());
25    new_soa
26        .user_names
27        .iter_mut()
28        .for_each(|id| *id = "PUBLIC".to_owned());
29    new_soa
30        .user_ids
31        .iter_mut()
32        .for_each(|id| *id = Guid::default());
33
34    // convert the owners struct of arrays into bytes using the owners schema
35    let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
36
37    let patch = BrPendingFs::Root(vec![(
38        "World".to_owned(),
39        BrPendingFs::Folder(Some(vec![(
40            "0".to_string(),
41            BrPendingFs::Folder(Some(vec![(
42                "Owners.mps".to_string(),
43                BrPendingFs::File(Some(content)),
44            )])),
45        )])),
46    )]);
47
48    // use .to_pending_patch() if you want to update the same world
49    let pending = db.to_pending()?.with_patch(patch)?;
50    if dst.exists() {
51        std::fs::remove_file(&dst)?;
52    }
53    Brz::write_pending(&dst, pending)?;
54
55    println!("{}", Brz::open(&dst)?.into_reader().owners_soa()?);
56
57    Ok(())
58}
More examples
Hide additional examples
examples/world_owner_counts.rs (line 39)
21fn main() -> Result<(), Box<dyn std::error::Error>> {
22    let mut args = std::env::args().into_iter();
23    args.next();
24    let Some(file) = args.next() else {
25        eprintln!("missing world file arg");
26        process::exit(1);
27    };
28
29    let dst = env::current_dir()?.join(PathBuf::from(&file));
30    if !dst.exists() {
31        eprintln!("file {} does not exist", dst.display());
32        process::exit(1);
33    }
34
35    eprintln!("Opening world: {}", path::absolute(&dst)?.display());
36
37    let db = Brdb::open(dst)?.into_reader();
38
39    let owners_soa = db.owners_soa()?.to_value();
40    let owners = OwnerTableSoA::try_from(&owners_soa)?;
41
42    let rows = (0..owners.user_ids.len())
43        .map(|i| {
44            let user_id = &owners.user_ids[i];
45            let display_name = &owners.display_names[i];
46            let user_name = &owners.user_names[i];
47            let entity_count = owners.entity_counts[i];
48            let brick_count = owners.brick_counts[i];
49            let component_count = owners.component_counts[i];
50            let wire_count = owners.wire_counts[i];
51            Row {
52                user_id: user_id.uuid().to_string(),
53                user_name: user_name.clone(),
54                display_name: display_name.clone(),
55                entity_counts: entity_count,
56                brick_counts: brick_count,
57                component_counts: component_count,
58                wire_counts: wire_count,
59            }
60        })
61        .collect::<Vec<_>>();
62    print!("{}", serde_json::to_string_pretty(&rows)?);
63
64    Ok(())
65}
examples/world_owner_tool.rs (line 37)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    let mut args = std::env::args().into_iter().peekable();
8    let cmd = args.next().unwrap();
9    if !args.peek().is_some() {
10        println!("usage: {cmd} show world.brdb");
11        println!("usage: {cmd} apply world.brdb owners.csv");
12        println!(
13            "owners.csv must be `display_name,user_name,user_id,old_user_id` where old_user_id is the one to replace."
14        );
15        process::exit(0);
16    }
17
18    let command = args.next().unwrap();
19    if command != "show" && command != "apply" {
20        eprintln!("unknown command. expected `show` or `apply`");
21        process::exit(1);
22    }
23
24    let Some(file) = args.next() else {
25        eprintln!("missing world file arg");
26        process::exit(1);
27    };
28
29    let dst = PathBuf::from(&file);
30    if !dst.exists() {
31        eprintln!("file {file} does not exist");
32        process::exit(1);
33    }
34
35    let db = Brdb::open(dst)?.into_reader();
36
37    let owners = db.owners_soa()?;
38
39    if command == "show" {
40        if args.peek().is_some() {
41            eprintln!("too many arguments!");
42            process::exit(1);
43        }
44
45        let owners_csv = owners
46            .prop("DisplayNames")?
47            .as_array()?
48            .iter()
49            .zip(owners.prop("UserNames")?.as_array()?.iter())
50            .zip(owners.prop("UserIds")?.as_array()?.iter())
51            .map(|((display_name, user_name), user_id)| {
52                format!(
53                    "{},{},{}",
54                    display_name.as_str().unwrap(),
55                    user_name.as_str().unwrap(),
56                    Guid::try_from(user_id).unwrap().uuid(),
57                )
58            })
59            .collect::<Vec<_>>();
60        println!("display_name,user_name,user_id\n{}", owners_csv.join("\n"));
61    } else if command == "apply" {
62        let Some(apply_file) = args.next() else {
63            eprintln!("missing owners csv file arg");
64            process::exit(1);
65        };
66        if args.peek().is_some() {
67            eprintln!("too many arguments!");
68            process::exit(1);
69        }
70
71        let apply_path = PathBuf::from(&apply_file);
72        if !apply_path.exists() {
73            eprintln!("file {apply_file} does not exist");
74            process::exit(1);
75        }
76
77        let mut display_name_index = None;
78        let mut user_name_index = None;
79        let mut user_id_index = None;
80        let mut old_user_id_index = None;
81        let mut apply_data = String::new();
82        File::open(apply_path)?.read_to_string(&mut apply_data)?;
83        let Some((header, rows)) = apply_data.split_once("\n") else {
84            eprintln!("file {apply_file} does not have any rows");
85            process::exit(1);
86        };
87        for (i, key) in header.split(",").enumerate() {
88            match key.trim().to_ascii_lowercase().as_ref() {
89                "display_name" => {
90                    display_name_index = Some(i);
91                }
92                "user_name" => {
93                    user_name_index = Some(i);
94                }
95                "user_id" => {
96                    user_id_index = Some(i);
97                }
98                "old_user_id" => old_user_id_index = Some(i),
99                other => {
100                    eprintln!("unknown column {other} in {apply_file}");
101                    process::exit(1);
102                }
103            }
104        }
105
106        let missing = [
107            ("display_name", display_name_index.is_none()),
108            ("user_name", user_name_index.is_none()),
109            ("user_id", user_id_index.is_none()),
110            ("old_user_id", old_user_id_index.is_none()),
111        ]
112        .into_iter()
113        .filter_map(|(k, cond)| cond.then_some(k.to_owned()))
114        .collect::<Vec<_>>();
115        if !missing.is_empty() {
116            eprintln!("missing columns: {}", missing.join(","));
117            process::exit(1);
118        }
119
120        let display_name_index = display_name_index.unwrap();
121        let user_name_index = user_name_index.unwrap();
122        let user_id_index = user_id_index.unwrap();
123        let old_user_id_index = old_user_id_index.unwrap();
124
125        // Parse the owners from BrdbValues
126        let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
127        let owners_lut = rows
128            .trim()
129            .split("\n")
130            .map(|r| r.trim().split(",").collect::<Vec<&str>>())
131            .map(|cols| {
132                let user_name = cols[user_name_index];
133                let display_name = cols[display_name_index];
134                let user_id = Uuid::parse_str(&cols[user_id_index])
135                    .expect(&format!("invalid uuid: {}", cols[user_id_index]));
136                let old_user_id = Uuid::parse_str(&cols[old_user_id_index])
137                    .expect(&format!("invalid old uuid: {}", cols[old_user_id_index]));
138                (old_user_id, (user_name, display_name, user_id))
139            })
140            .collect::<HashMap<_, _>>();
141        println!("{owners_lut:?}");
142
143        let mut changes = 0;
144
145        for i in 0..new_soa.user_ids.len() {
146            let old_id = new_soa.user_ids[i].uuid();
147            let Some((user_name, display_name, user_id)) = owners_lut.get(&old_id) else {
148                println!("missing old id for {old_id} - ignoring");
149                continue;
150            };
151            println!("replacing {old_id} with {user_id} - {user_name} ({display_name})");
152            new_soa.user_names[i] = (*user_name).to_owned();
153            new_soa.display_names[i] = (*display_name).to_owned();
154            new_soa.user_ids[i] = Guid::from_uuid((*user_id).clone());
155            changes += 1;
156        }
157
158        if changes == 0 {
159            println!("world left unchanged");
160            std::process::exit(0);
161        }
162
163        // convert the owners struct of arrays into bytes using the owners schema
164        let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
165
166        let patch = BrPendingFs::Root(vec![(
167            "World".to_owned(),
168            BrPendingFs::Folder(Some(vec![(
169                "0".to_string(),
170                BrPendingFs::Folder(Some(vec![(
171                    "Owners.mps".to_string(),
172                    BrPendingFs::File(Some(content)),
173                )])),
174            )])),
175        )]);
176        db.write_pending("Replace owners", db.to_pending_patch()?.with_patch(patch)?)?;
177        println!("revision created")
178    }
179
180    Ok(())
181}
Source

pub fn owners_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the Owners schema at a specific revision

Source

pub fn owners_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the Owners schema (latest revision)

Examples found in repository?
examples/world_replace_owner.rs (line 35)
7fn main() -> Result<(), Box<dyn std::error::Error>> {
8    let src = PathBuf::from("world.brdb");
9    let dst = PathBuf::from("world_patched.brz");
10
11    assert!(src.exists());
12
13    let db = Brdb::open(src)?.into_reader();
14
15    let owners = db.owners_soa()?;
16
17    // Parse the owners from BrdbValues
18    let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
19
20    // Modify the owner ids
21    new_soa
22        .display_names
23        .iter_mut()
24        .for_each(|id| *id = "PUBLIC".to_owned());
25    new_soa
26        .user_names
27        .iter_mut()
28        .for_each(|id| *id = "PUBLIC".to_owned());
29    new_soa
30        .user_ids
31        .iter_mut()
32        .for_each(|id| *id = Guid::default());
33
34    // convert the owners struct of arrays into bytes using the owners schema
35    let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
36
37    let patch = BrPendingFs::Root(vec![(
38        "World".to_owned(),
39        BrPendingFs::Folder(Some(vec![(
40            "0".to_string(),
41            BrPendingFs::Folder(Some(vec![(
42                "Owners.mps".to_string(),
43                BrPendingFs::File(Some(content)),
44            )])),
45        )])),
46    )]);
47
48    // use .to_pending_patch() if you want to update the same world
49    let pending = db.to_pending()?.with_patch(patch)?;
50    if dst.exists() {
51        std::fs::remove_file(&dst)?;
52    }
53    Brz::write_pending(&dst, pending)?;
54
55    println!("{}", Brz::open(&dst)?.into_reader().owners_soa()?);
56
57    Ok(())
58}
More examples
Hide additional examples
examples/world_owner_tool.rs (line 164)
6fn main() -> Result<(), Box<dyn std::error::Error>> {
7    let mut args = std::env::args().into_iter().peekable();
8    let cmd = args.next().unwrap();
9    if !args.peek().is_some() {
10        println!("usage: {cmd} show world.brdb");
11        println!("usage: {cmd} apply world.brdb owners.csv");
12        println!(
13            "owners.csv must be `display_name,user_name,user_id,old_user_id` where old_user_id is the one to replace."
14        );
15        process::exit(0);
16    }
17
18    let command = args.next().unwrap();
19    if command != "show" && command != "apply" {
20        eprintln!("unknown command. expected `show` or `apply`");
21        process::exit(1);
22    }
23
24    let Some(file) = args.next() else {
25        eprintln!("missing world file arg");
26        process::exit(1);
27    };
28
29    let dst = PathBuf::from(&file);
30    if !dst.exists() {
31        eprintln!("file {file} does not exist");
32        process::exit(1);
33    }
34
35    let db = Brdb::open(dst)?.into_reader();
36
37    let owners = db.owners_soa()?;
38
39    if command == "show" {
40        if args.peek().is_some() {
41            eprintln!("too many arguments!");
42            process::exit(1);
43        }
44
45        let owners_csv = owners
46            .prop("DisplayNames")?
47            .as_array()?
48            .iter()
49            .zip(owners.prop("UserNames")?.as_array()?.iter())
50            .zip(owners.prop("UserIds")?.as_array()?.iter())
51            .map(|((display_name, user_name), user_id)| {
52                format!(
53                    "{},{},{}",
54                    display_name.as_str().unwrap(),
55                    user_name.as_str().unwrap(),
56                    Guid::try_from(user_id).unwrap().uuid(),
57                )
58            })
59            .collect::<Vec<_>>();
60        println!("display_name,user_name,user_id\n{}", owners_csv.join("\n"));
61    } else if command == "apply" {
62        let Some(apply_file) = args.next() else {
63            eprintln!("missing owners csv file arg");
64            process::exit(1);
65        };
66        if args.peek().is_some() {
67            eprintln!("too many arguments!");
68            process::exit(1);
69        }
70
71        let apply_path = PathBuf::from(&apply_file);
72        if !apply_path.exists() {
73            eprintln!("file {apply_file} does not exist");
74            process::exit(1);
75        }
76
77        let mut display_name_index = None;
78        let mut user_name_index = None;
79        let mut user_id_index = None;
80        let mut old_user_id_index = None;
81        let mut apply_data = String::new();
82        File::open(apply_path)?.read_to_string(&mut apply_data)?;
83        let Some((header, rows)) = apply_data.split_once("\n") else {
84            eprintln!("file {apply_file} does not have any rows");
85            process::exit(1);
86        };
87        for (i, key) in header.split(",").enumerate() {
88            match key.trim().to_ascii_lowercase().as_ref() {
89                "display_name" => {
90                    display_name_index = Some(i);
91                }
92                "user_name" => {
93                    user_name_index = Some(i);
94                }
95                "user_id" => {
96                    user_id_index = Some(i);
97                }
98                "old_user_id" => old_user_id_index = Some(i),
99                other => {
100                    eprintln!("unknown column {other} in {apply_file}");
101                    process::exit(1);
102                }
103            }
104        }
105
106        let missing = [
107            ("display_name", display_name_index.is_none()),
108            ("user_name", user_name_index.is_none()),
109            ("user_id", user_id_index.is_none()),
110            ("old_user_id", old_user_id_index.is_none()),
111        ]
112        .into_iter()
113        .filter_map(|(k, cond)| cond.then_some(k.to_owned()))
114        .collect::<Vec<_>>();
115        if !missing.is_empty() {
116            eprintln!("missing columns: {}", missing.join(","));
117            process::exit(1);
118        }
119
120        let display_name_index = display_name_index.unwrap();
121        let user_name_index = user_name_index.unwrap();
122        let user_id_index = user_id_index.unwrap();
123        let old_user_id_index = old_user_id_index.unwrap();
124
125        // Parse the owners from BrdbValues
126        let mut new_soa = OwnerTableSoA::try_from(&owners.to_value())?;
127        let owners_lut = rows
128            .trim()
129            .split("\n")
130            .map(|r| r.trim().split(",").collect::<Vec<&str>>())
131            .map(|cols| {
132                let user_name = cols[user_name_index];
133                let display_name = cols[display_name_index];
134                let user_id = Uuid::parse_str(&cols[user_id_index])
135                    .expect(&format!("invalid uuid: {}", cols[user_id_index]));
136                let old_user_id = Uuid::parse_str(&cols[old_user_id_index])
137                    .expect(&format!("invalid old uuid: {}", cols[old_user_id_index]));
138                (old_user_id, (user_name, display_name, user_id))
139            })
140            .collect::<HashMap<_, _>>();
141        println!("{owners_lut:?}");
142
143        let mut changes = 0;
144
145        for i in 0..new_soa.user_ids.len() {
146            let old_id = new_soa.user_ids[i].uuid();
147            let Some((user_name, display_name, user_id)) = owners_lut.get(&old_id) else {
148                println!("missing old id for {old_id} - ignoring");
149                continue;
150            };
151            println!("replacing {old_id} with {user_id} - {user_name} ({display_name})");
152            new_soa.user_names[i] = (*user_name).to_owned();
153            new_soa.display_names[i] = (*display_name).to_owned();
154            new_soa.user_ids[i] = Guid::from_uuid((*user_id).clone());
155            changes += 1;
156        }
157
158        if changes == 0 {
159            println!("world left unchanged");
160            std::process::exit(0);
161        }
162
163        // convert the owners struct of arrays into bytes using the owners schema
164        let content = db.owners_schema()?.write_brdb(OWNER_TABLE_SOA, &new_soa)?;
165
166        let patch = BrPendingFs::Root(vec![(
167            "World".to_owned(),
168            BrPendingFs::Folder(Some(vec![(
169                "0".to_string(),
170                BrPendingFs::Folder(Some(vec![(
171                    "Owners.mps".to_string(),
172                    BrPendingFs::File(Some(content)),
173                )])),
174            )])),
175        )]);
176        db.write_pending("Replace owners", db.to_pending_patch()?.with_patch(patch)?)?;
177        println!("revision created")
178    }
179
180    Ok(())
181}
Source

pub fn components_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared components chunk schema at a specific revision

Source

pub fn components_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared components chunk schema (latest revision)

Examples found in repository?
examples/read_brz.rs (line 16)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
More examples
Hide additional examples
examples/world_move_bricks.rs (line 44)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    println!("Warning - This code will break if the brick chunk struct changes!!");
10
11    let db = Brdb::open(path)?.into_reader();
12
13    let data = db.global_data()?;
14    let mut grid = UnsavedGrid::default();
15
16    let mut total_bricks = 0;
17    for chunk in db.brick_chunk_index(1)? {
18        for brick in db
19            .brick_chunk_soa(1, chunk.index)?
20            .iter_bricks(chunk.index, data.clone())
21        {
22            // If we wanted wires/components, we'd need to track the bricks here by their chunk index and brick index
23            total_bricks += 1;
24
25            let mut brick = brick?;
26            brick.position += Position::new(3000, 0, 0);
27            grid.add_brick(data.as_ref(), &brick);
28        }
29
30        if chunk.num_components > 0 {
31            println!("sorry, this example doesn't handle components");
32        }
33        if chunk.num_wires > 0 {
34            println!("sorry, this example doesn't handle wires");
35        }
36    }
37    println!("{total_bricks} bricks");
38
39    let mut pending = db.to_pending()?;
40
41    // Replace the main grid (1) with the grid we created
42    *pending.cd_mut("World/0/Bricks/Grids/1")? = grid.to_pending(
43        data.proc_brick_starting_index(),
44        db.components_schema()?.as_ref(),
45    )?;
46
47    if dst.exists() {
48        std::fs::remove_file(&dst)?;
49    }
50    Brdb::new(&dst)?.write_pending("Move the bricks", pending)?;
51
52    // Verify bricks can be read
53    let db = Brdb::open(dst)?.into_reader();
54    for chunk in db.brick_chunk_index(1)? {
55        let _ = db.brick_chunk_soa(1, chunk.index)?;
56    }
57
58    Ok(())
59}
examples/read_world.rs (line 23)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/world_remove_shadows.rs (line 30)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let mut grid_ids = vec![1];
14
15    // Iterate all entity chunks to find dynamic brick grids...
16    // This could totally be a helper function
17    for index in db.entity_chunk_index()? {
18        for e in db.entity_chunk(index)? {
19            // Ensure the chunk is a dynamic brick grid
20            if !e.is_brick_grid() {
21                continue;
22            }
23            let Some(id) = e.id else {
24                continue;
25            };
26            grid_ids.push(id);
27        }
28    }
29
30    let component_schema = db.components_schema()?;
31    let mut grids_files = vec![];
32
33    // Iterate all grids (there can be bricks on entities)
34    for grid in &grid_ids {
35        let chunks = db.brick_chunk_index(*grid)?;
36        let mut chunk_files = vec![];
37        let mut num_grid_modified = 0;
38
39        // Iterate all chunks in the grid
40        for index in chunks {
41            let mut num_chunk_modified = 0;
42            if index.num_components == 0 {
43                println!("ignoring grid {grid} chunk {} with no components", *index);
44                continue;
45            }
46
47            // Iterate all the components in the chunk
48            let (mut soa, components) = db.component_chunk(*grid, *index)?;
49            for mut s in components {
50                // Disable the shadow casting property if it's present and true
51                if s.prop("bCastShadows")
52                    .is_ok_and(|v| v.as_brdb_bool().unwrap_or_default())
53                {
54                    println!(
55                        "grid {grid} chunk {} mutating component {}",
56                        *index,
57                        s.get_name()
58                    );
59                    s.set_prop("bCastShadows", BrdbValue::Bool(false))?;
60                    num_grid_modified += 1;
61                    num_chunk_modified += 1;
62                }
63
64                soa.unwritten_struct_data.push(Box::new(s));
65            }
66
67            if num_chunk_modified == 0 {
68                continue;
69            }
70
71            chunk_files.push((
72                format!("{}.mps", *index),
73                // ComponentChunkSoA::to_bytes ensures the extra data is written after the SoA data
74                BrPendingFs::File(Some(soa.to_bytes(&component_schema)?)),
75            ));
76        }
77
78        if num_grid_modified == 0 {
79            println!("grid {grid} has no shadow-casting components, skipping");
80            continue;
81        } else {
82            println!(
83                "grid {grid} has {num_grid_modified} shadow-casting components in {} files",
84                chunk_files.len()
85            );
86        }
87
88        grids_files.push((
89            grid.to_string(),
90            BrPendingFs::Folder(Some(vec![(
91                "Components".to_string(),
92                BrPendingFs::Folder(Some(chunk_files)),
93            )])),
94        ))
95    }
96
97    let patch = BrPendingFs::Root(vec![(
98        "World".to_owned(),
99        BrPendingFs::Folder(Some(vec![(
100            "0".to_string(),
101            BrPendingFs::Folder(Some(vec![(
102                "Bricks".to_string(),
103                BrPendingFs::Folder(Some(vec![(
104                    "Grids".to_string(),
105                    BrPendingFs::Folder(Some(grids_files)),
106                )])),
107            )])),
108        )])),
109    )]);
110
111    // Use .to_pending_patch() if you want to update the same world
112    let pending = db.to_pending()?.with_patch(patch)?;
113    if dst.exists() {
114        std::fs::remove_file(&dst)?;
115    }
116    Brdb::new(&dst)?.write_pending("Disable Shadow Casting", pending)?;
117
118    // Ensure all the components can be read
119    let db = Brdb::open(dst)?.into_reader();
120    for grid in grid_ids {
121        let chunks = db.brick_chunk_index(grid)?;
122        for index in chunks {
123            if index.num_components == 0 {
124                continue;
125            }
126            let (_soa, _components) = db.component_chunk(grid, *index)?;
127        }
128    }
129
130    Ok(())
131}
examples/extract_defaults.rs (line 110)
104fn main() -> Result<(), Box<dyn std::error::Error>> {
105    let args: Vec<String> = std::env::args().collect();
106    let path = PathBuf::from(args.get(1).expect("usage: extract_defaults <dump.brdb> [output.rs]"));
107    let output_path = args.get(2).map(PathBuf::from);
108    let db = Brdb::open(path)?.into_reader();
109    let global_data = db.global_data()?;
110    let schema = db.components_schema()?;
111
112    let mut type_to_struct: BTreeMap<String, String> = BTreeMap::new();
113    let mut wire_ports: BTreeSet<String> = BTreeSet::new();
114    let mut struct_defaults: BTreeMap<String, Vec<(String, String, String)>> = BTreeMap::new();
115
116    for (i, type_name) in global_data.component_type_names.iter().enumerate() {
117        if let Some(struct_name) = global_data.component_data_struct_names.get(i) {
118            if struct_name != "None" {
119                type_to_struct.insert(type_name.clone(), struct_name.clone());
120            }
121        }
122    }
123
124    for port in &global_data.component_wire_port_names {
125        wire_ports.insert(port.clone());
126    }
127
128    for chunk in db.brick_chunk_index(1)? {
129        if chunk.num_components == 0 {
130            continue;
131        }
132        let Ok((_soa, components)) = db.component_chunk(1, *chunk) else {
133            continue;
134        };
135        for s in components {
136            let name = s.get_name().to_owned();
137            if struct_defaults.contains_key(&name) {
138                continue;
139            }
140
141            let Some(struct_def) = schema.get_struct(&name) else {
142                continue;
143            };
144            let s_id = match schema.intern.get(&name) {
145                Some(id) => id,
146                None => continue,
147            };
148
149            let mut fields = Vec::new();
150            for (field_id, prop_ty) in struct_def {
151                let field_name = match field_id.get(&schema) {
152                    Some(n) => n.to_owned(),
153                    None => continue,
154                };
155                let ty_str = match prop_ty {
156                    BrdbSchemaStructProperty::Type(t) => {
157                        match schema.intern.lookup_ref(*t) {
158                            Some(s) => s.to_owned(),
159                            None => continue,
160                        }
161                    }
162                    _ => continue,
163                };
164                let val = match s.as_brdb_struct_prop_value(&schema, s_id, *field_id) {
165                    Ok(v) => v,
166                    Err(_) => continue,
167                };
168                let formatted = match format_value(&schema, &ty_str, val) {
169                    Some(f) => f,
170                    None => continue,
171                };
172                fields.push((field_name, ty_str, formatted));
173            }
174            struct_defaults.insert(name, fields);
175        }
176    }
177
178    use std::fmt::Write;
179    let mut out = String::new();
180    macro_rules! w { ($($t:tt)*) => { writeln!(out, $($t)*).unwrap() } }
181
182    w!("// Autogenerated from: cargo run --example extract_defaults -- path/to/dump.brdb");
183    w!();
184
185    w!("pub static COMPONENT_TYPE_STRUCT_PAIRS: &[(&str, &str)] = &[");
186    for (type_name, struct_name) in &type_to_struct {
187        w!("    (\"{type_name}\", \"{struct_name}\"),");
188    }
189    w!("];");
190    w!();
191
192    w!("pub static WIRE_PORT_NAMES: &[&str] = &[");
193    for port in &wire_ports {
194        w!("    \"{port}\",");
195    }
196    w!("];");
197    w!();
198
199    w!("pub static ENTITY_TYPE_STRUCT_PAIRS: &[(&str, &str)] = &[");
200    for (i, type_name) in global_data.entity_type_names.iter().enumerate() {
201        if let Some(class_name) = global_data.entity_data_class_names.get_index(i) {
202            w!("    (\"{type_name}\", \"{class_name}\"),");
203        }
204    }
205    w!("];");
206    w!();
207
208    w!("use std::sync::LazyLock;");
209    // WireVariant is only referenced when a dump carries wire-variant defaults;
210    // allow it to be unused so a dump without any still compiles clean.
211    w!("#[allow(unused_imports)]");
212    w!("use crate::schema::WireVariant;");
213    w!("use crate::schema::as_brdb::AsBrdbValue;");
214    // NestedStructDefault carries struct-typed defaults (Vector2D/LinearColor/...); allow it
215    // to be unused so a dump without any nested-struct defaults still compiles clean.
216    w!("#[allow(unused_imports)]");
217    w!("use crate::schema::as_brdb::NestedStructDefault;");
218    w!("use crate::SavedBrickColor;");
219    w!();
220    w!("/// Default field values for every component data struct.");
221    w!("pub static STRUCT_DEFAULTS: LazyLock<Vec<(&'static str, Vec<(&'static str, Box<dyn AsBrdbValue>)>)>> =");
222    w!("    LazyLock::new(|| vec![");
223    let mut first_entry = true;
224    for (name, fields) in &struct_defaults {
225        if fields.is_empty() {
226            continue;
227        }
228        w!("        (\"{name}\", vec![");
229        for (field_name, _ty, val) in fields {
230            if first_entry {
231                w!("            (\"{field_name}\", {val}),");
232                first_entry = false;
233            } else {
234                let short = val.trim_end_matches(" as Box<dyn AsBrdbValue>");
235                w!("            (\"{field_name}\", {short}),");
236            }
237        }
238        w!("        ]),");
239    }
240    w!("    ]);");
241
242    if let Some(ref p) = output_path {
243        std::fs::write(p, &out)?;
244        eprintln!("Wrote {}", p.display());
245    } else {
246        print!("{out}");
247    }
248
249    eprintln!(
250        "Extracted: {} type mappings, {} wire ports, {} struct defaults, {} entity types",
251        type_to_struct.len(),
252        wire_ports.len(),
253        struct_defaults.len(),
254        global_data.entity_type_names.len(),
255    );
256
257    Ok(())
258}
examples/read_wire_ports.rs (line 24)
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}
Source

pub fn component_chunk_soa( &self, grid_id: usize, chunk: ChunkIndex, ) -> Result<(ComponentChunkSoA, Vec<BrdbStruct>), BrError>
where T: BrFsReader,

Read the shared component chunks

Examples found in repository?
examples/read_brz.rs (line 24)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
More examples
Hide additional examples
examples/read_components.rs (line 27)
4fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
5    println!(
6        "Component types: {:?}",
7        db.global_data()?.component_type_names
8    );
9    println!(
10        "Component structs: {:?}",
11        db.global_data()?.component_data_struct_names
12    );
13    // Probe grid ids 1.. until one is missing (covers the main grid plus any
14    // microchip inner grids, which entity discovery may not surface).
15    for gid in 1..32 {
16        let chunks = match db.brick_chunk_index(gid) {
17            Ok(c) => c,
18            Err(_) => break,
19        };
20        println!("=== grid {gid} ===");
21        for chunk in chunks {
22            println!(
23                "chunk {} bricks={} components={} wires={}",
24                chunk.index, chunk.num_bricks, chunk.num_components, chunk.num_wires
25            );
26            if chunk.num_components > 0 {
27                match db.component_chunk_soa(gid, chunk.index) {
28                    Ok((_soa, components)) => {
29                        for c in components {
30                            println!("  component: {c}");
31                        }
32                    }
33                    Err(e) => {
34                        println!("  ERROR reading components: {e}");
35                        return Err(e.into());
36                    }
37                }
38            }
39        }
40    }
41    Ok(())
42}
examples/read_world.rs (line 50)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/read_wire_ports.rs (line 62)
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}
examples/validate_wires.rs (line 52)
18fn run<T: brdb::BrFsReader>(
19    db: brdb::BrReader<T>,
20) -> Result<(), Box<dyn std::error::Error>> {
21    let data = db.global_data()?;
22
23    // Collect all grid ids: main grid (1) + every brick-grid entity.
24    let mut grid_ids = vec![1usize];
25    for index in db.entity_chunk_index()? {
26        for e in db.entity_chunk(index)? {
27            if e.is_brick_grid() || e.is_microchip_grid() {
28                if let Some(id) = e.id {
29                    grid_ids.push(id);
30                }
31            }
32        }
33    }
34
35    // Pass 1: per (grid, chunk) build brick component lists + brick counts.
36    // brick_components[(gid, chunk)][brick_index] = Vec<component_type_index>
37    let mut brick_counts: HashMap<(usize, String), usize> = HashMap::new();
38    let mut brick_components: HashMap<(usize, String), HashMap<u32, Vec<u16>>> = HashMap::new();
39    let mut brick_types: HashMap<(usize, String), Vec<u32>> = HashMap::new();
40    for &gid in &grid_ids {
41        let chunks = match db.brick_chunk_index(gid) {
42            Ok(c) => c,
43            Err(_) => continue,
44        };
45        for chunk in &chunks {
46            let key = (gid, format!("{:?}", chunk.index));
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            brick_counts.insert(key.clone(), soa.brick_type_indices.len());
49            brick_types.insert(key.clone(), soa.brick_type_indices.clone());
50            let mut per_brick: HashMap<u32, Vec<u16>> = HashMap::new();
51            if chunk.num_components > 0 {
52                let (csoa, _components) = db.component_chunk_soa(gid, chunk.index)?;
53                let type_indices: Vec<u16> = csoa
54                    .component_type_counters
55                    .iter()
56                    .flat_map(|v| {
57                        let index = v.type_index as u16;
58                        (0..v.num_instances).map(move |_| index)
59                    })
60                    .collect();
61                for (i, bi) in csoa.component_brick_indices.iter().enumerate() {
62                    let brick_index = *bi;
63                    per_brick.entry(brick_index).or_default().push(type_indices[i]);
64                }
65            }
66            brick_components.insert(key, per_brick);
67        }
68    }
69
70    let cname = |t: u16| -> String {
71        data.component_type_names
72            .get_index(t as usize)
73            .map(|s| s.to_string())
74            .unwrap_or_else(|| format!("<type {t}>"))
75    };
76    let pname = |p: u16| -> String {
77        data.component_wire_port_names
78            .get_index(p as usize)
79            .map(|s| s.to_string())
80            .unwrap_or_else(|| format!("<port {p}>"))
81    };
82
83    // Pass 2: validate wires.
84    let mut total = 0u64;
85    let mut bad = 0u64;
86    for &gid in &grid_ids {
87        let chunks = match db.brick_chunk_index(gid) {
88            Ok(c) => c,
89            Err(_) => continue,
90        };
91        for chunk in &chunks {
92            if chunk.num_wires == 0 {
93                continue;
94            }
95            let key = (gid, format!("{:?}", chunk.index));
96            let soa = db.wire_chunk_soa(gid, chunk.index)?.to_value();
97            let soa: WireChunkSoA = (&soa).try_into()?;
98
99            let mut check = |ctx: &str,
100                             ggid: usize,
101                             ckey: &str,
102                             brick_index: u32,
103                             ct: u16,
104                             port: u16| {
105                total += 1;
106                let k = (ggid, ckey.to_string());
107                let n = brick_counts.get(&k).copied().unwrap_or(0);
108                if brick_index as usize >= n {
109                    bad += 1;
110                    println!(
111                        "BAD {ctx}: grid {ggid} chunk {ckey} brick {brick_index} OUT OF RANGE (chunk has {n} bricks); wanted {} {}",
112                        cname(ct),
113                        pname(port)
114                    );
115                    return;
116                }
117                let comps = brick_components
118                    .get(&k)
119                    .and_then(|m| m.get(&brick_index))
120                    .cloned()
121                    .unwrap_or_default();
122                if !comps.contains(&ct) {
123                    bad += 1;
124                    println!(
125                        "BAD {ctx}: grid {ggid} chunk {ckey} brick {brick_index} has components [{}] but wire wants {} {}",
126                        comps.iter().map(|c| cname(*c)).collect::<Vec<_>>().join(", "),
127                        cname(ct),
128                        pname(port)
129                    );
130                }
131            };
132
133            for p in &soa.local_wire_sources {
134                check("local-src", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
135            }
136            for p in &soa.local_wire_targets {
137                check("local-tgt", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
138            }
139            for p in &soa.remote_wire_sources {
140                let ckey = format!("{:?}", p.chunk_index);
141                check(
142                    "remote-src",
143                    p.grid_persistent_index as usize,
144                    &ckey,
145                    p.brick_index_in_chunk,
146                    p.component_type_index,
147                    p.port_index,
148                );
149            }
150            // Remote wires: the source names another grid; the target is
151            // local to THIS chunk.
152            for p in &soa.remote_wire_targets {
153                check("remote-tgt", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
154            }
155        }
156    }
157
158    println!("validated {total} wire endpoints, {bad} bad");
159
160    // Optional dump: grid + index range, e.g. `-- file 2 580 590`
161    let args: Vec<String> = std::env::args().collect();
162    if args.len() >= 5 {
163        let gid: usize = args[2].parse()?;
164        let lo: u32 = args[3].parse()?;
165        let hi: u32 = args[4].parse()?;
166        for ((g, ckey), types) in &brick_types {
167            if *g != gid {
168                continue;
169            }
170            for i in lo..=hi.min(types.len().saturating_sub(1) as u32) {
171                let comps = brick_components
172                    .get(&(gid, ckey.clone()))
173                    .and_then(|m| m.get(&i))
174                    .cloned()
175                    .unwrap_or_default();
176                let asset = data
177                    .basic_brick_asset_names
178                    .get_index(types[i as usize] as usize)
179                    .map(|s| s.to_string())
180                    .unwrap_or_else(|| format!("<pb {}>", types[i as usize]));
181                println!(
182                    "grid {gid} chunk {ckey} brick {i}: {asset} [{}]",
183                    comps.iter().map(|c| cname(*c)).collect::<Vec<_>>().join(", ")
184                );
185            }
186        }
187    }
188    Ok(())
189}
examples/dump_fixture.rs (line 58)
11fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
12    let data = db.global_data()?;
13    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
14    println!("Procedural Brick assets: {:?}", data.procedural_brick_asset_names);
15    // register_all_components() embeds the FULL catalog (hundreds of wire
16    // ports/component types), so only print counts for those — the fixture's
17    // OWN types/ports are visible per-brick below via the type-name lookups.
18    println!(
19        "Wire port count: {} (registered catalog)",
20        data.component_wire_port_names.len()
21    );
22    println!(
23        "Component type count: {} (registered catalog)",
24        data.component_type_names.len()
25    );
26    println!("Entity types: {:?}", data.entity_type_names);
27    println!("Entity classes: {:?}", data.entity_data_class_names);
28
29    // Probe grid ids 1.. until one is missing (grid 1 is always the main
30    // grid; higher ids are sub-grids / microchip inner grids).
31    for gid in 1..32 {
32        let chunks = match db.brick_chunk_index(gid) {
33            Ok(c) => c,
34            Err(_) => break,
35        };
36        println!("=== grid {gid} ===");
37        println!("Brick chunks: {chunks:?}");
38        for chunk in &chunks {
39            let soa = db.brick_chunk_soa(gid, chunk.index)?;
40            println!("Brick soa: {soa:?}");
41            let asset_names: Vec<String> = soa
42                .brick_type_indices
43                .iter()
44                .map(|&t| {
45                    if (t as usize) < soa.procedural_brick_starting_index as usize {
46                        data.basic_brick_asset_names
47                            .get_index(t as usize)
48                            .cloned()
49                            .unwrap_or_default()
50                    } else {
51                        "<procedural>".to_string()
52                    }
53                })
54                .collect();
55            println!("Brick asset names (by index in chunk): {asset_names:?}");
56
57            if chunk.num_components > 0 {
58                let (soa, components) = db.component_chunk_soa(gid, chunk.index)?;
59                let type_names: Vec<String> = soa
60                    .component_type_counters
61                    .iter()
62                    .flat_map(|c| {
63                        let name = data
64                            .component_type_names
65                            .get_index(c.type_index as usize)
66                            .cloned()
67                            .unwrap_or_default();
68                        (0..c.num_instances).map(move |_| name.clone())
69                    })
70                    .collect();
71                println!(
72                    "Component chunk soa: component_brick_indices={:?} microchip_brick_indices={:?} microchip_brick_grid_references={:?}",
73                    soa.component_brick_indices,
74                    soa.microchip_brick_indices,
75                    soa.microchip_brick_grid_references
76                );
77                println!("Component type names (parallel to ComponentBrickIndices): {type_names:?}");
78                for c in components {
79                    println!("Component: {c}");
80                }
81            }
82            if chunk.num_wires > 0 {
83                let raw = db.wire_chunk_soa(gid, chunk.index)?;
84                println!("Wire chunk soa (raw struct): {raw}");
85                let value = raw.to_value();
86                let soa: WireChunkSoA = (&value).try_into()?;
87                let port_name = |i: u16| {
88                    data.component_wire_port_names
89                        .get_index(i as usize)
90                        .cloned()
91                        .unwrap_or_default()
92                };
93                let type_name = |i: u16| {
94                    data.component_type_names
95                        .get_index(i as usize)
96                        .cloned()
97                        .unwrap_or_default()
98                };
99                for s in &soa.local_wire_sources {
100                    println!(
101                        "  local source: brick_in_chunk={} type={} port={}",
102                        s.brick_index_in_chunk,
103                        type_name(s.component_type_index),
104                        port_name(s.port_index)
105                    );
106                }
107                for t in &soa.local_wire_targets {
108                    println!(
109                        "  local target: brick_in_chunk={} type={} port={}",
110                        t.brick_index_in_chunk,
111                        type_name(t.component_type_index),
112                        port_name(t.port_index)
113                    );
114                }
115                for s in &soa.remote_wire_sources {
116                    println!(
117                        "  remote source: grid_persistent_index={} chunk={} brick_in_chunk={} type={} port={}",
118                        s.grid_persistent_index,
119                        s.chunk_index,
120                        s.brick_index_in_chunk,
121                        type_name(s.component_type_index),
122                        port_name(s.port_index)
123                    );
124                }
125                for t in &soa.remote_wire_targets {
126                    println!(
127                        "  remote target: brick_in_chunk={} type={} port={}",
128                        t.brick_index_in_chunk,
129                        type_name(t.component_type_index),
130                        port_name(t.port_index)
131                    );
132                }
133            }
134        }
135    }
136
137    // Entity chunks (present whenever the world has any grids/entities).
138    let entity_chunk_indices = db.entity_chunk_index()?;
139    println!("=== entities ===");
140    println!("Entity chunk indices: {entity_chunk_indices:?}");
141    for chunk_index in entity_chunk_indices {
142        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
143        println!("--- Chunk {chunk_index} (SoA) ---");
144        println!("Type counters: {:?}", soa.type_counters);
145        let type_names: Vec<String> = soa
146            .type_counters
147            .iter()
148            .flat_map(|c| {
149                let name = data
150                    .entity_type_names
151                    .get_index(c.type_index as usize)
152                    .cloned()
153                    .unwrap_or_default();
154                (0..c.num_entities).map(move |_| name.clone())
155            })
156            .collect();
157        println!("Entity type names (parallel to PersistentIndices): {type_names:?}");
158        println!("Persistent indices: {:?}", soa.persistent_indices);
159        println!("Locations: {:?}", soa.locations);
160        println!("Rotations: {:?}", soa.rotations);
161        println!("Physics locked (frozen): {:?}", soa.physics_locked_flags);
162        println!("Physics sleeping: {:?}", soa.physics_sleeping_flags);
163        for (i, data) in entity_data.iter().enumerate() {
164            match data {
165                Some(struct_data) => println!("  Entity {i} struct: {struct_data}"),
166                None => println!("  Entity {i}: None"),
167            }
168        }
169    }
170
171    println!("Files: {}", db.get_fs()?.render());
172
173    Ok(())
174}
Source

pub fn component_chunk( &self, grid_id: usize, chunk: ChunkIndex, ) -> Result<(ComponentChunkSoA, Vec<BrdbStruct>), BrError>
where T: BrFsReader,

Read the shared component chunks

Examples found in repository?
examples/world_remove_shadows.rs (line 48)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let mut grid_ids = vec![1];
14
15    // Iterate all entity chunks to find dynamic brick grids...
16    // This could totally be a helper function
17    for index in db.entity_chunk_index()? {
18        for e in db.entity_chunk(index)? {
19            // Ensure the chunk is a dynamic brick grid
20            if !e.is_brick_grid() {
21                continue;
22            }
23            let Some(id) = e.id else {
24                continue;
25            };
26            grid_ids.push(id);
27        }
28    }
29
30    let component_schema = db.components_schema()?;
31    let mut grids_files = vec![];
32
33    // Iterate all grids (there can be bricks on entities)
34    for grid in &grid_ids {
35        let chunks = db.brick_chunk_index(*grid)?;
36        let mut chunk_files = vec![];
37        let mut num_grid_modified = 0;
38
39        // Iterate all chunks in the grid
40        for index in chunks {
41            let mut num_chunk_modified = 0;
42            if index.num_components == 0 {
43                println!("ignoring grid {grid} chunk {} with no components", *index);
44                continue;
45            }
46
47            // Iterate all the components in the chunk
48            let (mut soa, components) = db.component_chunk(*grid, *index)?;
49            for mut s in components {
50                // Disable the shadow casting property if it's present and true
51                if s.prop("bCastShadows")
52                    .is_ok_and(|v| v.as_brdb_bool().unwrap_or_default())
53                {
54                    println!(
55                        "grid {grid} chunk {} mutating component {}",
56                        *index,
57                        s.get_name()
58                    );
59                    s.set_prop("bCastShadows", BrdbValue::Bool(false))?;
60                    num_grid_modified += 1;
61                    num_chunk_modified += 1;
62                }
63
64                soa.unwritten_struct_data.push(Box::new(s));
65            }
66
67            if num_chunk_modified == 0 {
68                continue;
69            }
70
71            chunk_files.push((
72                format!("{}.mps", *index),
73                // ComponentChunkSoA::to_bytes ensures the extra data is written after the SoA data
74                BrPendingFs::File(Some(soa.to_bytes(&component_schema)?)),
75            ));
76        }
77
78        if num_grid_modified == 0 {
79            println!("grid {grid} has no shadow-casting components, skipping");
80            continue;
81        } else {
82            println!(
83                "grid {grid} has {num_grid_modified} shadow-casting components in {} files",
84                chunk_files.len()
85            );
86        }
87
88        grids_files.push((
89            grid.to_string(),
90            BrPendingFs::Folder(Some(vec![(
91                "Components".to_string(),
92                BrPendingFs::Folder(Some(chunk_files)),
93            )])),
94        ))
95    }
96
97    let patch = BrPendingFs::Root(vec![(
98        "World".to_owned(),
99        BrPendingFs::Folder(Some(vec![(
100            "0".to_string(),
101            BrPendingFs::Folder(Some(vec![(
102                "Bricks".to_string(),
103                BrPendingFs::Folder(Some(vec![(
104                    "Grids".to_string(),
105                    BrPendingFs::Folder(Some(grids_files)),
106                )])),
107            )])),
108        )])),
109    )]);
110
111    // Use .to_pending_patch() if you want to update the same world
112    let pending = db.to_pending()?.with_patch(patch)?;
113    if dst.exists() {
114        std::fs::remove_file(&dst)?;
115    }
116    Brdb::new(&dst)?.write_pending("Disable Shadow Casting", pending)?;
117
118    // Ensure all the components can be read
119    let db = Brdb::open(dst)?.into_reader();
120    for grid in grid_ids {
121        let chunks = db.brick_chunk_index(grid)?;
122        for index in chunks {
123            if index.num_components == 0 {
124                continue;
125            }
126            let (_soa, _components) = db.component_chunk(grid, *index)?;
127        }
128    }
129
130    Ok(())
131}
More examples
Hide additional examples
examples/extract_defaults.rs (line 132)
104fn main() -> Result<(), Box<dyn std::error::Error>> {
105    let args: Vec<String> = std::env::args().collect();
106    let path = PathBuf::from(args.get(1).expect("usage: extract_defaults <dump.brdb> [output.rs]"));
107    let output_path = args.get(2).map(PathBuf::from);
108    let db = Brdb::open(path)?.into_reader();
109    let global_data = db.global_data()?;
110    let schema = db.components_schema()?;
111
112    let mut type_to_struct: BTreeMap<String, String> = BTreeMap::new();
113    let mut wire_ports: BTreeSet<String> = BTreeSet::new();
114    let mut struct_defaults: BTreeMap<String, Vec<(String, String, String)>> = BTreeMap::new();
115
116    for (i, type_name) in global_data.component_type_names.iter().enumerate() {
117        if let Some(struct_name) = global_data.component_data_struct_names.get(i) {
118            if struct_name != "None" {
119                type_to_struct.insert(type_name.clone(), struct_name.clone());
120            }
121        }
122    }
123
124    for port in &global_data.component_wire_port_names {
125        wire_ports.insert(port.clone());
126    }
127
128    for chunk in db.brick_chunk_index(1)? {
129        if chunk.num_components == 0 {
130            continue;
131        }
132        let Ok((_soa, components)) = db.component_chunk(1, *chunk) else {
133            continue;
134        };
135        for s in components {
136            let name = s.get_name().to_owned();
137            if struct_defaults.contains_key(&name) {
138                continue;
139            }
140
141            let Some(struct_def) = schema.get_struct(&name) else {
142                continue;
143            };
144            let s_id = match schema.intern.get(&name) {
145                Some(id) => id,
146                None => continue,
147            };
148
149            let mut fields = Vec::new();
150            for (field_id, prop_ty) in struct_def {
151                let field_name = match field_id.get(&schema) {
152                    Some(n) => n.to_owned(),
153                    None => continue,
154                };
155                let ty_str = match prop_ty {
156                    BrdbSchemaStructProperty::Type(t) => {
157                        match schema.intern.lookup_ref(*t) {
158                            Some(s) => s.to_owned(),
159                            None => continue,
160                        }
161                    }
162                    _ => continue,
163                };
164                let val = match s.as_brdb_struct_prop_value(&schema, s_id, *field_id) {
165                    Ok(v) => v,
166                    Err(_) => continue,
167                };
168                let formatted = match format_value(&schema, &ty_str, val) {
169                    Some(f) => f,
170                    None => continue,
171                };
172                fields.push((field_name, ty_str, formatted));
173            }
174            struct_defaults.insert(name, fields);
175        }
176    }
177
178    use std::fmt::Write;
179    let mut out = String::new();
180    macro_rules! w { ($($t:tt)*) => { writeln!(out, $($t)*).unwrap() } }
181
182    w!("// Autogenerated from: cargo run --example extract_defaults -- path/to/dump.brdb");
183    w!();
184
185    w!("pub static COMPONENT_TYPE_STRUCT_PAIRS: &[(&str, &str)] = &[");
186    for (type_name, struct_name) in &type_to_struct {
187        w!("    (\"{type_name}\", \"{struct_name}\"),");
188    }
189    w!("];");
190    w!();
191
192    w!("pub static WIRE_PORT_NAMES: &[&str] = &[");
193    for port in &wire_ports {
194        w!("    \"{port}\",");
195    }
196    w!("];");
197    w!();
198
199    w!("pub static ENTITY_TYPE_STRUCT_PAIRS: &[(&str, &str)] = &[");
200    for (i, type_name) in global_data.entity_type_names.iter().enumerate() {
201        if let Some(class_name) = global_data.entity_data_class_names.get_index(i) {
202            w!("    (\"{type_name}\", \"{class_name}\"),");
203        }
204    }
205    w!("];");
206    w!();
207
208    w!("use std::sync::LazyLock;");
209    // WireVariant is only referenced when a dump carries wire-variant defaults;
210    // allow it to be unused so a dump without any still compiles clean.
211    w!("#[allow(unused_imports)]");
212    w!("use crate::schema::WireVariant;");
213    w!("use crate::schema::as_brdb::AsBrdbValue;");
214    // NestedStructDefault carries struct-typed defaults (Vector2D/LinearColor/...); allow it
215    // to be unused so a dump without any nested-struct defaults still compiles clean.
216    w!("#[allow(unused_imports)]");
217    w!("use crate::schema::as_brdb::NestedStructDefault;");
218    w!("use crate::SavedBrickColor;");
219    w!();
220    w!("/// Default field values for every component data struct.");
221    w!("pub static STRUCT_DEFAULTS: LazyLock<Vec<(&'static str, Vec<(&'static str, Box<dyn AsBrdbValue>)>)>> =");
222    w!("    LazyLock::new(|| vec![");
223    let mut first_entry = true;
224    for (name, fields) in &struct_defaults {
225        if fields.is_empty() {
226            continue;
227        }
228        w!("        (\"{name}\", vec![");
229        for (field_name, _ty, val) in fields {
230            if first_entry {
231                w!("            (\"{field_name}\", {val}),");
232                first_entry = false;
233            } else {
234                let short = val.trim_end_matches(" as Box<dyn AsBrdbValue>");
235                w!("            (\"{field_name}\", {short}),");
236            }
237        }
238        w!("        ]),");
239    }
240    w!("    ]);");
241
242    if let Some(ref p) = output_path {
243        std::fs::write(p, &out)?;
244        eprintln!("Wrote {}", p.display());
245    } else {
246        print!("{out}");
247    }
248
249    eprintln!(
250        "Extracted: {} type mappings, {} wire ports, {} struct defaults, {} entity types",
251        type_to_struct.len(),
252        wire_ports.len(),
253        struct_defaults.len(),
254        global_data.entity_type_names.len(),
255    );
256
257    Ok(())
258}
Source

pub fn wires_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared wires chunk schema at a specific revision

Source

pub fn wires_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared wires chunk schema (latest revision)

Source

pub fn wire_chunk_soa( &self, grid_id: usize, chunk: ChunkIndex, ) -> Result<BrdbStruct, BrError>
where T: BrFsReader,

Examples found in repository?
examples/read_brz.rs (line 30)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
More examples
Hide additional examples
examples/read_world.rs (line 57)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/read_wire_ports.rs (line 102)
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}
examples/validate_wires.rs (line 96)
18fn run<T: brdb::BrFsReader>(
19    db: brdb::BrReader<T>,
20) -> Result<(), Box<dyn std::error::Error>> {
21    let data = db.global_data()?;
22
23    // Collect all grid ids: main grid (1) + every brick-grid entity.
24    let mut grid_ids = vec![1usize];
25    for index in db.entity_chunk_index()? {
26        for e in db.entity_chunk(index)? {
27            if e.is_brick_grid() || e.is_microchip_grid() {
28                if let Some(id) = e.id {
29                    grid_ids.push(id);
30                }
31            }
32        }
33    }
34
35    // Pass 1: per (grid, chunk) build brick component lists + brick counts.
36    // brick_components[(gid, chunk)][brick_index] = Vec<component_type_index>
37    let mut brick_counts: HashMap<(usize, String), usize> = HashMap::new();
38    let mut brick_components: HashMap<(usize, String), HashMap<u32, Vec<u16>>> = HashMap::new();
39    let mut brick_types: HashMap<(usize, String), Vec<u32>> = HashMap::new();
40    for &gid in &grid_ids {
41        let chunks = match db.brick_chunk_index(gid) {
42            Ok(c) => c,
43            Err(_) => continue,
44        };
45        for chunk in &chunks {
46            let key = (gid, format!("{:?}", chunk.index));
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            brick_counts.insert(key.clone(), soa.brick_type_indices.len());
49            brick_types.insert(key.clone(), soa.brick_type_indices.clone());
50            let mut per_brick: HashMap<u32, Vec<u16>> = HashMap::new();
51            if chunk.num_components > 0 {
52                let (csoa, _components) = db.component_chunk_soa(gid, chunk.index)?;
53                let type_indices: Vec<u16> = csoa
54                    .component_type_counters
55                    .iter()
56                    .flat_map(|v| {
57                        let index = v.type_index as u16;
58                        (0..v.num_instances).map(move |_| index)
59                    })
60                    .collect();
61                for (i, bi) in csoa.component_brick_indices.iter().enumerate() {
62                    let brick_index = *bi;
63                    per_brick.entry(brick_index).or_default().push(type_indices[i]);
64                }
65            }
66            brick_components.insert(key, per_brick);
67        }
68    }
69
70    let cname = |t: u16| -> String {
71        data.component_type_names
72            .get_index(t as usize)
73            .map(|s| s.to_string())
74            .unwrap_or_else(|| format!("<type {t}>"))
75    };
76    let pname = |p: u16| -> String {
77        data.component_wire_port_names
78            .get_index(p as usize)
79            .map(|s| s.to_string())
80            .unwrap_or_else(|| format!("<port {p}>"))
81    };
82
83    // Pass 2: validate wires.
84    let mut total = 0u64;
85    let mut bad = 0u64;
86    for &gid in &grid_ids {
87        let chunks = match db.brick_chunk_index(gid) {
88            Ok(c) => c,
89            Err(_) => continue,
90        };
91        for chunk in &chunks {
92            if chunk.num_wires == 0 {
93                continue;
94            }
95            let key = (gid, format!("{:?}", chunk.index));
96            let soa = db.wire_chunk_soa(gid, chunk.index)?.to_value();
97            let soa: WireChunkSoA = (&soa).try_into()?;
98
99            let mut check = |ctx: &str,
100                             ggid: usize,
101                             ckey: &str,
102                             brick_index: u32,
103                             ct: u16,
104                             port: u16| {
105                total += 1;
106                let k = (ggid, ckey.to_string());
107                let n = brick_counts.get(&k).copied().unwrap_or(0);
108                if brick_index as usize >= n {
109                    bad += 1;
110                    println!(
111                        "BAD {ctx}: grid {ggid} chunk {ckey} brick {brick_index} OUT OF RANGE (chunk has {n} bricks); wanted {} {}",
112                        cname(ct),
113                        pname(port)
114                    );
115                    return;
116                }
117                let comps = brick_components
118                    .get(&k)
119                    .and_then(|m| m.get(&brick_index))
120                    .cloned()
121                    .unwrap_or_default();
122                if !comps.contains(&ct) {
123                    bad += 1;
124                    println!(
125                        "BAD {ctx}: grid {ggid} chunk {ckey} brick {brick_index} has components [{}] but wire wants {} {}",
126                        comps.iter().map(|c| cname(*c)).collect::<Vec<_>>().join(", "),
127                        cname(ct),
128                        pname(port)
129                    );
130                }
131            };
132
133            for p in &soa.local_wire_sources {
134                check("local-src", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
135            }
136            for p in &soa.local_wire_targets {
137                check("local-tgt", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
138            }
139            for p in &soa.remote_wire_sources {
140                let ckey = format!("{:?}", p.chunk_index);
141                check(
142                    "remote-src",
143                    p.grid_persistent_index as usize,
144                    &ckey,
145                    p.brick_index_in_chunk,
146                    p.component_type_index,
147                    p.port_index,
148                );
149            }
150            // Remote wires: the source names another grid; the target is
151            // local to THIS chunk.
152            for p in &soa.remote_wire_targets {
153                check("remote-tgt", gid, &key.1, p.brick_index_in_chunk, p.component_type_index, p.port_index);
154            }
155        }
156    }
157
158    println!("validated {total} wire endpoints, {bad} bad");
159
160    // Optional dump: grid + index range, e.g. `-- file 2 580 590`
161    let args: Vec<String> = std::env::args().collect();
162    if args.len() >= 5 {
163        let gid: usize = args[2].parse()?;
164        let lo: u32 = args[3].parse()?;
165        let hi: u32 = args[4].parse()?;
166        for ((g, ckey), types) in &brick_types {
167            if *g != gid {
168                continue;
169            }
170            for i in lo..=hi.min(types.len().saturating_sub(1) as u32) {
171                let comps = brick_components
172                    .get(&(gid, ckey.clone()))
173                    .and_then(|m| m.get(&i))
174                    .cloned()
175                    .unwrap_or_default();
176                let asset = data
177                    .basic_brick_asset_names
178                    .get_index(types[i as usize] as usize)
179                    .map(|s| s.to_string())
180                    .unwrap_or_else(|| format!("<pb {}>", types[i as usize]));
181                println!(
182                    "grid {gid} chunk {ckey} brick {i}: {asset} [{}]",
183                    comps.iter().map(|c| cname(*c)).collect::<Vec<_>>().join(", ")
184                );
185            }
186        }
187    }
188    Ok(())
189}
examples/dump_fixture.rs (line 83)
11fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
12    let data = db.global_data()?;
13    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
14    println!("Procedural Brick assets: {:?}", data.procedural_brick_asset_names);
15    // register_all_components() embeds the FULL catalog (hundreds of wire
16    // ports/component types), so only print counts for those — the fixture's
17    // OWN types/ports are visible per-brick below via the type-name lookups.
18    println!(
19        "Wire port count: {} (registered catalog)",
20        data.component_wire_port_names.len()
21    );
22    println!(
23        "Component type count: {} (registered catalog)",
24        data.component_type_names.len()
25    );
26    println!("Entity types: {:?}", data.entity_type_names);
27    println!("Entity classes: {:?}", data.entity_data_class_names);
28
29    // Probe grid ids 1.. until one is missing (grid 1 is always the main
30    // grid; higher ids are sub-grids / microchip inner grids).
31    for gid in 1..32 {
32        let chunks = match db.brick_chunk_index(gid) {
33            Ok(c) => c,
34            Err(_) => break,
35        };
36        println!("=== grid {gid} ===");
37        println!("Brick chunks: {chunks:?}");
38        for chunk in &chunks {
39            let soa = db.brick_chunk_soa(gid, chunk.index)?;
40            println!("Brick soa: {soa:?}");
41            let asset_names: Vec<String> = soa
42                .brick_type_indices
43                .iter()
44                .map(|&t| {
45                    if (t as usize) < soa.procedural_brick_starting_index as usize {
46                        data.basic_brick_asset_names
47                            .get_index(t as usize)
48                            .cloned()
49                            .unwrap_or_default()
50                    } else {
51                        "<procedural>".to_string()
52                    }
53                })
54                .collect();
55            println!("Brick asset names (by index in chunk): {asset_names:?}");
56
57            if chunk.num_components > 0 {
58                let (soa, components) = db.component_chunk_soa(gid, chunk.index)?;
59                let type_names: Vec<String> = soa
60                    .component_type_counters
61                    .iter()
62                    .flat_map(|c| {
63                        let name = data
64                            .component_type_names
65                            .get_index(c.type_index as usize)
66                            .cloned()
67                            .unwrap_or_default();
68                        (0..c.num_instances).map(move |_| name.clone())
69                    })
70                    .collect();
71                println!(
72                    "Component chunk soa: component_brick_indices={:?} microchip_brick_indices={:?} microchip_brick_grid_references={:?}",
73                    soa.component_brick_indices,
74                    soa.microchip_brick_indices,
75                    soa.microchip_brick_grid_references
76                );
77                println!("Component type names (parallel to ComponentBrickIndices): {type_names:?}");
78                for c in components {
79                    println!("Component: {c}");
80                }
81            }
82            if chunk.num_wires > 0 {
83                let raw = db.wire_chunk_soa(gid, chunk.index)?;
84                println!("Wire chunk soa (raw struct): {raw}");
85                let value = raw.to_value();
86                let soa: WireChunkSoA = (&value).try_into()?;
87                let port_name = |i: u16| {
88                    data.component_wire_port_names
89                        .get_index(i as usize)
90                        .cloned()
91                        .unwrap_or_default()
92                };
93                let type_name = |i: u16| {
94                    data.component_type_names
95                        .get_index(i as usize)
96                        .cloned()
97                        .unwrap_or_default()
98                };
99                for s in &soa.local_wire_sources {
100                    println!(
101                        "  local source: brick_in_chunk={} type={} port={}",
102                        s.brick_index_in_chunk,
103                        type_name(s.component_type_index),
104                        port_name(s.port_index)
105                    );
106                }
107                for t in &soa.local_wire_targets {
108                    println!(
109                        "  local target: brick_in_chunk={} type={} port={}",
110                        t.brick_index_in_chunk,
111                        type_name(t.component_type_index),
112                        port_name(t.port_index)
113                    );
114                }
115                for s in &soa.remote_wire_sources {
116                    println!(
117                        "  remote source: grid_persistent_index={} chunk={} brick_in_chunk={} type={} port={}",
118                        s.grid_persistent_index,
119                        s.chunk_index,
120                        s.brick_index_in_chunk,
121                        type_name(s.component_type_index),
122                        port_name(s.port_index)
123                    );
124                }
125                for t in &soa.remote_wire_targets {
126                    println!(
127                        "  remote target: brick_in_chunk={} type={} port={}",
128                        t.brick_index_in_chunk,
129                        type_name(t.component_type_index),
130                        port_name(t.port_index)
131                    );
132                }
133            }
134        }
135    }
136
137    // Entity chunks (present whenever the world has any grids/entities).
138    let entity_chunk_indices = db.entity_chunk_index()?;
139    println!("=== entities ===");
140    println!("Entity chunk indices: {entity_chunk_indices:?}");
141    for chunk_index in entity_chunk_indices {
142        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
143        println!("--- Chunk {chunk_index} (SoA) ---");
144        println!("Type counters: {:?}", soa.type_counters);
145        let type_names: Vec<String> = soa
146            .type_counters
147            .iter()
148            .flat_map(|c| {
149                let name = data
150                    .entity_type_names
151                    .get_index(c.type_index as usize)
152                    .cloned()
153                    .unwrap_or_default();
154                (0..c.num_entities).map(move |_| name.clone())
155            })
156            .collect();
157        println!("Entity type names (parallel to PersistentIndices): {type_names:?}");
158        println!("Persistent indices: {:?}", soa.persistent_indices);
159        println!("Locations: {:?}", soa.locations);
160        println!("Rotations: {:?}", soa.rotations);
161        println!("Physics locked (frozen): {:?}", soa.physics_locked_flags);
162        println!("Physics sleeping: {:?}", soa.physics_sleeping_flags);
163        for (i, data) in entity_data.iter().enumerate() {
164            match data {
165                Some(struct_data) => println!("  Entity {i} struct: {struct_data}"),
166                None => println!("  Entity {i}: None"),
167            }
168        }
169    }
170
171    println!("Files: {}", db.get_fs()?.render());
172
173    Ok(())
174}
examples/extract_components.rs (line 109)
18fn main() -> Result<(), Box<dyn std::error::Error>> {
19    let args: Vec<String> = std::env::args().collect();
20    let path = PathBuf::from(
21        args.get(1)
22            .expect("usage: extract_components <zoo.brdb> [out.rs]"),
23    );
24    let out_path = args.get(2).map(PathBuf::from);
25    let db = Brdb::open(path)?.into_reader();
26    let data = db.global_data()?;
27
28    // The standalone phase attaches otherwise-brickless components to this generic host for
29    // probing; it is never a real component host, so it is filtered out of the host lists.
30    let standalone_host_brick = brdb::assets::bricks::B_1X1F_ROUND;
31    let standalone_host: &str = standalone_host_brick.asset().as_ref();
32
33    // component type index -> host brick asset name(s) / wire port indices.
34    // Host names are resolved inline (basic and procedural bricks index different
35    // name sets), so this stores names rather than type indices.
36    let mut bricks: BTreeMap<u16, BTreeSet<String>> = BTreeMap::new();
37    let mut inputs: BTreeMap<u16, BTreeSet<u16>> = BTreeMap::new();
38    let mut outputs: BTreeMap<u16, BTreeSet<u16>> = BTreeMap::new();
39
40    // Grid 1 is the main grid; higher ids are microchip inner grids. Probe
41    // until a grid id is missing (same convention as read_components).
42    for gid in 1..64 {
43        let chunks = match db.brick_chunk_index(gid) {
44            Ok(c) => c,
45            Err(_) => break,
46        };
47        for chunk in &chunks {
48            // brick index -> brick type index (basic-brick asset), for the
49            // host-brick mapping.
50            let bsoa = db.brick_chunk_soa(gid, chunk.index)?;
51            let pb_start = bsoa.procedural_brick_starting_index;
52            // Procedural brick type index (>= pb_start) -> procedural asset index, via the
53            // per-size run-length counters (same expansion SoA::iter_bricks uses).
54            let proc_asset_by_size: Vec<u32> = bsoa
55                .brick_size_counters
56                .iter()
57                .flat_map(|c| std::iter::repeat(c.asset_index).take(c.num_sizes as usize))
58                .collect();
59            let brick_types = bsoa.brick_type_indices;
60
61            if chunk.num_components > 0 {
62                // component_chunk's Vec<BrdbStruct> only contains STRUCT-BEARING components
63                // (it skips whole counters whose type has no data struct, e.g. some
64                // Component_Internal_* gates), so its len() < the per-instance total. Looping
65                // `0..components.len()` truncated the per-instance type/brick arrays, dropping
66                // the host brick of any component in the tail (e.g. Component_Internal_InputSplitter).
67                // Iterate the FULL per-instance count instead, matching brs-js's reader.
68                let (csoa, _components) = db.component_chunk_soa(gid, chunk.index)?;
69                let brick_indices = csoa.component_brick_indices;
70                // Expand run-length (type_index, num_instances) into a flat
71                // per-instance list of component type indices.
72                let type_indices = csoa
73                    .component_type_counters
74                    .iter()
75                    .flat_map(|v| {
76                        let ti = v.type_index as u16;
77                        (0..v.num_instances).map(move |_| ti)
78                    })
79                    .collect::<Vec<_>>();
80                for i in 0..type_indices.len() {
81                    let comp_ty = type_indices[i];
82                    // ensure every placed component is present even with no wires
83                    inputs.entry(comp_ty).or_default();
84                    outputs.entry(comp_ty).or_default();
85                    let brick_index = brick_indices[i].as_brdb_u32()? as usize;
86                    if let Some(&bt) = brick_types.get(brick_index) {
87                        // Basic bricks index basic_brick_asset_names directly; procedural
88                        // bricks (type index >= pb_start) map through the size run-lengths to
89                        // a procedural_brick_asset_names index.
90                        let host = if bt < pb_start {
91                            data.basic_brick_asset_names.get_index(bt as usize).cloned()
92                        } else {
93                            proc_asset_by_size
94                                .get((bt - pb_start) as usize)
95                                .and_then(|&ai| {
96                                    data.procedural_brick_asset_names.get_index(ai as usize).cloned()
97                                })
98                        };
99                        if let Some(host) = host {
100                            if host != standalone_host {
101                                bricks.entry(comp_ty).or_default().insert(host);
102                            }
103                        }
104                    }
105                }
106            }
107
108            if chunk.num_wires > 0 {
109                let soa = db.wire_chunk_soa(gid, chunk.index)?.to_value();
110                let soa: WireChunkSoA = (&soa).try_into()?;
111                // local and remote ports are distinct types, so handle each in
112                // its own loop (they share component_type_index / port_index).
113                for p in &soa.local_wire_sources {
114                    outputs
115                        .entry(p.component_type_index)
116                        .or_default()
117                        .insert(p.port_index);
118                }
119                for p in &soa.remote_wire_sources {
120                    outputs
121                        .entry(p.component_type_index)
122                        .or_default()
123                        .insert(p.port_index);
124                }
125                for p in &soa.local_wire_targets {
126                    inputs
127                        .entry(p.component_type_index)
128                        .or_default()
129                        .insert(p.port_index);
130                }
131                for p in &soa.remote_wire_targets {
132                    inputs
133                        .entry(p.component_type_index)
134                        .or_default()
135                        .insert(p.port_index);
136                }
137            }
138        }
139    }
140
141    // Resolve indices to names.
142    let name_of = |idx: u16| data.component_type_names.get_index(idx as usize).cloned();
143    let port_of = |idx: u16| data.component_wire_port_names.get_index(idx as usize).cloned();
144
145    let all: BTreeSet<u16> = bricks
146        .keys()
147        .chain(inputs.keys())
148        .chain(outputs.keys())
149        .copied()
150        .collect();
151
152    // (name, host bricks, input ports, output ports), sorted by name.
153    let mut rows: Vec<(String, Vec<String>, Vec<String>, Vec<String>)> = Vec::new();
154    for ty in all {
155        let Some(name) = name_of(ty) else { continue };
156        let mut bs: Vec<String> = bricks
157            .get(&ty)
158            .map(|s| s.iter().cloned().collect())
159            .unwrap_or_default();
160        bs.sort();
161        bs.dedup();
162        let mut ins: Vec<String> = inputs
163            .get(&ty)
164            .map(|s| s.iter().filter_map(|&p| port_of(p)).collect())
165            .unwrap_or_default();
166        ins.sort();
167        ins.dedup();
168        let mut outs: Vec<String> = outputs
169            .get(&ty)
170            .map(|s| s.iter().filter_map(|&p| port_of(p)).collect())
171            .unwrap_or_default();
172        outs.sort();
173        outs.dedup();
174        rows.push((name, bs, ins, outs));
175    }
176    rows.sort_by(|a, b| a.0.cmp(&b.0));
177
178    let mut out = String::new();
179    macro_rules! w {
180        ($($t:tt)*) => { writeln!(out, $($t)*).unwrap() };
181    }
182    let slice = |v: &[String]| {
183        v.iter()
184            .map(|s| format!("{s:?}"))
185            .collect::<Vec<_>>()
186            .join(", ")
187    };
188
189    w!("// Autogenerated from a zoo save:");
190    w!("//   cargo run --example extract_components -- <zoo.brdb> src/assets/component_catalog.rs");
191    w!("// Do not edit by hand.");
192    w!();
193    w!("/// Per-component catalog entry: the full component type name, its host");
194    w!("/// brick asset(s), and its wire input/output port names. Extracted from a");
195    w!("/// fully-placed, fully-wired \"zoo\" save (mirrors brs-js's COMPONENTS).");
196    w!("#[derive(Debug, Clone, Copy, PartialEq, Eq)]");
197    w!("pub struct ComponentInfo {{");
198    w!("    /// e.g. \"BrickComponentType_WireGraph_Exec_Branch\".");
199    w!("    pub name: &'static str,");
200    w!("    /// Host brick asset name(s) that carry this component.");
201    w!("    pub bricks: &'static [&'static str],");
202    w!("    /// Wire input port names.");
203    w!("    pub inputs: &'static [&'static str],");
204    w!("    /// Wire output port names.");
205    w!("    pub outputs: &'static [&'static str],");
206    w!("}}");
207    w!();
208    w!("impl ComponentInfo {{");
209    w!("    /// The primary host brick asset (first, if any).");
210    w!("    pub const fn brick(&self) -> Option<&'static str> {{");
211    w!("        self.bricks.first().copied()");
212    w!("    }}");
213    w!("}}");
214    w!();
215    w!(
216        "/// Every component present in the zoo, sorted by `name` (binary-searchable)."
217    );
218    w!("pub static COMPONENTS: &[ComponentInfo] = &[");
219    for (name, bs, ins, outs) in &rows {
220        w!(
221            "    ComponentInfo {{ name: {name:?}, bricks: &[{}], inputs: &[{}], outputs: &[{}] }},",
222            slice(bs),
223            slice(ins),
224            slice(outs),
225        );
226    }
227    w!("];");
228    w!();
229    w!("/// Look up a component by its full type name.");
230    w!("pub fn component(name: &str) -> Option<&'static ComponentInfo> {{");
231    w!("    COMPONENTS");
232    w!("        .binary_search_by(|c| c.name.cmp(name))");
233    w!("        .ok()");
234    w!("        .map(|i| &COMPONENTS[i])");
235    w!("}}");
236
237    if let Some(ref p) = out_path {
238        std::fs::write(p, &out)?;
239        eprintln!("Wrote {}", p.display());
240    } else {
241        print!("{out}");
242    }
243    eprintln!(
244        "Extracted {} components ({} with host bricks)",
245        rows.len(),
246        rows.iter().filter(|r| !r.1.is_empty()).count(),
247    );
248    Ok(())
249}
Source

pub fn brick_chunk_index_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared brick-chunk-index schema at a specific revision

Source

pub fn brick_chunk_index_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared brick-chunk-index schema (latest revision)

Source

pub fn bricks_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared bricks chunk schema at a specific revision

Source

pub fn bricks_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared bricks chunk schema (latest revision)

Source

pub fn brick_chunk_index( &self, grid_id: usize, ) -> Result<Vec<ChunkMeta>, BrError>
where T: BrFsReader,

Read the brick chunk indices for a specific grid

Examples found in repository?
examples/count_wires.rs (line 26)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let path = PathBuf::from(
6        std::env::args()
7            .nth(1)
8            .unwrap_or_else(|| "world.brz".to_string()),
9    );
10    let db = Brz::open(path)?.into_reader();
11
12    let mut grid_ids = vec![1];
13    for index in db.entity_chunk_index()? {
14        for e in db.entity_chunk(index)? {
15            if e.is_brick_grid() || e.is_microchip_grid() {
16                if let Some(id) = e.id {
17                    grid_ids.push(id);
18                }
19            }
20        }
21    }
22
23    let mut total_wires = 0u64;
24    let mut total_bricks = 0u64;
25    for &gid in &grid_ids {
26        let chunks = db.brick_chunk_index(gid)?;
27        for chunk in &chunks {
28            total_bricks += chunk.num_bricks as u64;
29            total_wires += chunk.num_wires as u64;
30        }
31    }
32
33    println!("grids: {}", grid_ids.len());
34    println!("bricks: {total_bricks}");
35    println!("wires: {total_wires}");
36    Ok(())
37}
More examples
Hide additional examples
examples/read_brz.rs (line 18)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
examples/read_components.rs (line 16)
4fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
5    println!(
6        "Component types: {:?}",
7        db.global_data()?.component_type_names
8    );
9    println!(
10        "Component structs: {:?}",
11        db.global_data()?.component_data_struct_names
12    );
13    // Probe grid ids 1.. until one is missing (covers the main grid plus any
14    // microchip inner grids, which entity discovery may not surface).
15    for gid in 1..32 {
16        let chunks = match db.brick_chunk_index(gid) {
17            Ok(c) => c,
18            Err(_) => break,
19        };
20        println!("=== grid {gid} ===");
21        for chunk in chunks {
22            println!(
23                "chunk {} bricks={} components={} wires={}",
24                chunk.index, chunk.num_bricks, chunk.num_components, chunk.num_wires
25            );
26            if chunk.num_components > 0 {
27                match db.component_chunk_soa(gid, chunk.index) {
28                    Ok((_soa, components)) => {
29                        for c in components {
30                            println!("  component: {c}");
31                        }
32                    }
33                    Err(e) => {
34                        println!("  ERROR reading components: {e}");
35                        return Err(e.into());
36                    }
37                }
38            }
39        }
40    }
41    Ok(())
42}
examples/world_move_bricks.rs (line 17)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    println!("Warning - This code will break if the brick chunk struct changes!!");
10
11    let db = Brdb::open(path)?.into_reader();
12
13    let data = db.global_data()?;
14    let mut grid = UnsavedGrid::default();
15
16    let mut total_bricks = 0;
17    for chunk in db.brick_chunk_index(1)? {
18        for brick in db
19            .brick_chunk_soa(1, chunk.index)?
20            .iter_bricks(chunk.index, data.clone())
21        {
22            // If we wanted wires/components, we'd need to track the bricks here by their chunk index and brick index
23            total_bricks += 1;
24
25            let mut brick = brick?;
26            brick.position += Position::new(3000, 0, 0);
27            grid.add_brick(data.as_ref(), &brick);
28        }
29
30        if chunk.num_components > 0 {
31            println!("sorry, this example doesn't handle components");
32        }
33        if chunk.num_wires > 0 {
34            println!("sorry, this example doesn't handle wires");
35        }
36    }
37    println!("{total_bricks} bricks");
38
39    let mut pending = db.to_pending()?;
40
41    // Replace the main grid (1) with the grid we created
42    *pending.cd_mut("World/0/Bricks/Grids/1")? = grid.to_pending(
43        data.proc_brick_starting_index(),
44        db.components_schema()?.as_ref(),
45    )?;
46
47    if dst.exists() {
48        std::fs::remove_file(&dst)?;
49    }
50    Brdb::new(&dst)?.write_pending("Move the bricks", pending)?;
51
52    // Verify bricks can be read
53    let db = Brdb::open(dst)?.into_reader();
54    for chunk in db.brick_chunk_index(1)? {
55        let _ = db.brick_chunk_soa(1, chunk.index)?;
56    }
57
58    Ok(())
59}
examples/read_world.rs (line 44)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/inspect_grids.rs (line 32)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from(
7        std::env::args()
8            .nth(1)
9            .unwrap_or_else(|| "world.brz".to_string()),
10    );
11    let db = Brz::open(path)?.into_reader();
12
13    let mut grid_ids = vec![1];
14    for index in db.entity_chunk_index()? {
15        for e in db.entity_chunk(index)? {
16            if e.is_brick_grid() || e.is_microchip_grid() {
17                if let Some(id) = e.id {
18                    grid_ids.push(id);
19                }
20            }
21        }
22    }
23
24    // For each grid, collect a fingerprint: (num_bricks, num_wires, num_chunks)
25    // to find grids that look identical.
26    let mut fingerprints: HashMap<(u64, u64, usize), Vec<usize>> = HashMap::new();
27    let mut total_bricks = 0u64;
28    let mut total_wires = 0u64;
29    let mut total_components = 0u64;
30
31    for &gid in &grid_ids {
32        let chunks = db.brick_chunk_index(gid)?;
33        let mut grid_bricks = 0u64;
34        let mut grid_wires = 0u64;
35        let mut grid_components = 0u64;
36        for chunk in &chunks {
37            grid_bricks += chunk.num_bricks as u64;
38            grid_wires += chunk.num_wires as u64;
39            grid_components += chunk.num_components as u64;
40        }
41        total_bricks += grid_bricks;
42        total_wires += grid_wires;
43        total_components += grid_components;
44
45        let fp = (grid_bricks, grid_wires, chunks.len());
46        fingerprints.entry(fp).or_default().push(gid);
47    }
48
49    println!("=== Grid Summary ===");
50    println!("total grids: {}", grid_ids.len());
51    println!("total bricks: {total_bricks}");
52    println!("total wires: {total_wires}");
53    println!("total components: {total_components}");
54    println!();
55
56    println!("=== Unique Grid Shapes ===");
57    let mut fps: Vec<_> = fingerprints.iter().collect();
58    fps.sort_by_key(|((b, _w, _), grids)| std::cmp::Reverse(*b * grids.len() as u64));
59
60    for ((bricks, wires, chunks), grids) in &fps {
61        let savings = if grids.len() > 1 {
62            format!(
63                " → {} could be deduplicated (save {} bricks, {} wires)",
64                grids.len() - 1,
65                bricks * (grids.len() as u64 - 1),
66                wires * (grids.len() as u64 - 1)
67            )
68        } else {
69            String::new()
70        };
71        println!(
72            "  {}×  ({} bricks, {} wires, {} chunks){}",
73            grids.len(),
74            bricks,
75            wires,
76            chunks,
77            savings
78        );
79    }
80
81    // Top 10 largest grids
82    println!();
83    println!("=== Top 10 Largest Grids ===");
84    let mut grid_sizes: Vec<(usize, u64, u64)> = Vec::new();
85    for &gid in &grid_ids {
86        let chunks = db.brick_chunk_index(gid)?;
87        let b: u64 = chunks.iter().map(|c| c.num_bricks as u64).sum();
88        let w: u64 = chunks.iter().map(|c| c.num_wires as u64).sum();
89        grid_sizes.push((gid, b, w));
90    }
91    grid_sizes.sort_by_key(|(_, b, _)| std::cmp::Reverse(*b));
92    for (gid, b, w) in grid_sizes.iter().take(10) {
93        println!("  grid {gid}: {b} bricks, {w} wires");
94    }
95
96    Ok(())
97}
Source

pub fn brick_chunk_soa( &self, grid_id: usize, chunk: ChunkIndex, ) -> Result<BrickChunkSoA, BrError>
where T: BrFsReader,

Examples found in repository?
examples/write_brick.rs (line 22)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_brick.brdb");
7
8    let mut world = World::new();
9    world.meta.bundle.description = "Example World".to_string();
10    world.bricks.push(Brick {
11        position: (0, 0, 6).into(),
12        color: (255, 0, 0).into(),
13        ..Default::default()
14    });
15
16    world.write_brdb(&path)?;
17
18    let db = Brdb::new(&path)?.into_reader();
19
20    println!("file structure: {}", db.get_fs()?.render());
21
22    let soa = db.brick_chunk_soa(1, (0, 0, 0).into())?;
23    let color = soa.colors_and_alphas[0];
24    assert_eq!(color.r, 255);
25    assert_eq!(color.g, 0);
26    assert_eq!(color.b, 0);
27    assert_eq!(color.a, 5);
28
29    Ok(())
30}
More examples
Hide additional examples
examples/write_brz.rs (line 25)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_brick.brz");
7
8    let mut world = World::new();
9    world.meta.bundle.description = "Example World".to_string();
10    world.bricks.push(Brick {
11        position: (0, 0, 6).into(),
12        color: (255, 0, 0).into(),
13        ..Default::default()
14    });
15
16    if path.exists() {
17        std::fs::remove_file(&path)?;
18    }
19    world.write_brz(&path)?;
20
21    let db = Brz::new(&path)?.into_reader();
22
23    println!("{}", db.get_fs()?.render());
24
25    let soa = db.brick_chunk_soa(1, (0, 0, 0).into())?;
26    let color = soa.colors_and_alphas[0];
27    assert_eq!(color.r, 255);
28    assert_eq!(color.g, 0);
29    assert_eq!(color.b, 0);
30    assert_eq!(color.a, 5);
31
32    Ok(())
33}
examples/read_brz.rs (line 21)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./world.brz");
7
8    // The API for reading a brz is identical to reading a Brdb
9    let db = Brz::open(path)?.into_reader();
10
11    let data = db.global_data()?;
12    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
13    println!("Wire ports: {:?}", data.component_wire_port_names);
14    println!("Component types: {:?}", data.component_type_names);
15    println!("Component structs: {:?}", data.component_data_struct_names);
16    println!("Component schemas: {}", db.components_schema()?);
17
18    let chunks = db.brick_chunk_index(1)?;
19    println!("Brick chunks: {chunks:?}");
20    for chunk in chunks {
21        let soa = db.brick_chunk_soa(1, chunk.index)?;
22        println!("Brick soa: {soa:?}");
23        if chunk.num_components > 0 {
24            let (_soa, components) = db.component_chunk_soa(1, chunk.index)?;
25            for c in components {
26                println!("Component: {c}");
27            }
28        }
29        if chunk.num_wires > 0 {
30            let soa = db.wire_chunk_soa(1, chunk.index)?;
31            println!("Wires soa: {soa}");
32        }
33    }
34
35    println!("Files: {}", db.get_fs()?.render());
36
37    Ok(())
38}
examples/world_move_bricks.rs (line 19)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    println!("Warning - This code will break if the brick chunk struct changes!!");
10
11    let db = Brdb::open(path)?.into_reader();
12
13    let data = db.global_data()?;
14    let mut grid = UnsavedGrid::default();
15
16    let mut total_bricks = 0;
17    for chunk in db.brick_chunk_index(1)? {
18        for brick in db
19            .brick_chunk_soa(1, chunk.index)?
20            .iter_bricks(chunk.index, data.clone())
21        {
22            // If we wanted wires/components, we'd need to track the bricks here by their chunk index and brick index
23            total_bricks += 1;
24
25            let mut brick = brick?;
26            brick.position += Position::new(3000, 0, 0);
27            grid.add_brick(data.as_ref(), &brick);
28        }
29
30        if chunk.num_components > 0 {
31            println!("sorry, this example doesn't handle components");
32        }
33        if chunk.num_wires > 0 {
34            println!("sorry, this example doesn't handle wires");
35        }
36    }
37    println!("{total_bricks} bricks");
38
39    let mut pending = db.to_pending()?;
40
41    // Replace the main grid (1) with the grid we created
42    *pending.cd_mut("World/0/Bricks/Grids/1")? = grid.to_pending(
43        data.proc_brick_starting_index(),
44        db.components_schema()?.as_ref(),
45    )?;
46
47    if dst.exists() {
48        std::fs::remove_file(&dst)?;
49    }
50    Brdb::new(&dst)?.write_pending("Move the bricks", pending)?;
51
52    // Verify bricks can be read
53    let db = Brdb::open(dst)?.into_reader();
54    for chunk in db.brick_chunk_index(1)? {
55        let _ = db.brick_chunk_soa(1, chunk.index)?;
56    }
57
58    Ok(())
59}
examples/read_world.rs (line 47)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/read_wire_ports.rs (line 38)
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}
Source

pub fn entities_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared entity chunk schema at a specific revision

Source

pub fn entities_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the shared entity chunk schema (latest revision)

Examples found in repository?
examples/world_freeze_entities.rs (line 14)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let chunks = db.entity_chunk_index()?;
14    let entity_schema = db.entities_schema()?;
15    let global_data = db.global_data()?;
16    let mut chunk_files = vec![];
17
18    for index in chunks {
19        // Entity_chunk loads entities and their entity data
20        let entities = db.entity_chunk(index)?;
21
22        // Re-assemble the soa. using add_entity ensures the extra data is correctly handled
23        let mut soa = EntityChunkSoA::default();
24        for mut e in entities.into_iter() {
25            e.frozen = true;
26            soa.add_entity(&global_data, &e, e.id.unwrap() as u32);
27        }
28
29        chunk_files.push((
30            format!("{index}.mps"),
31            // EntityChunkSoA::to_bytes ensures the extra data is written after the SoA data
32            BrPendingFs::File(Some(soa.to_bytes(&entity_schema)?)),
33        ));
34    }
35
36    let patch = BrPendingFs::Root(vec![(
37        "World".to_owned(),
38        BrPendingFs::Folder(Some(vec![(
39            "0".to_string(),
40            BrPendingFs::Folder(Some(vec![(
41                "Entities".to_string(),
42                BrPendingFs::Folder(Some(vec![(
43                    "Chunks".to_string(),
44                    BrPendingFs::Folder(Some(chunk_files)),
45                )])),
46            )])),
47        )])),
48    )]);
49
50    // Use .to_pending_patch() if you want to update the same world
51    let pending = db.to_pending()?.with_patch(patch)?;
52    if dst.exists() {
53        std::fs::remove_file(&dst)?;
54    }
55    Brdb::new(&dst)?.write_pending("Freeze Entities", pending)?;
56
57    // Ensure entities can be read
58    let db = Brdb::open(dst)?.into_reader();
59    let chunks = db.entity_chunk_index()?;
60    for index in chunks {
61        let _ = db.entity_chunk(index)?;
62    }
63
64    Ok(())
65}
Source

pub fn entities_chunk_index_schema_rev( &self, revision: i64, ) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the entity chunk index schema at a specific revision

Source

pub fn entities_chunk_index_schema(&self) -> Result<Arc<BrdbSchema>, BrError>
where T: BrFsReader,

Read the entity chunk index schema (latest revision)

Source

pub fn entity_chunk_index(&self) -> Result<Vec<ChunkIndex>, BrError>
where T: BrFsReader,

Read the entity chunk indices

Examples found in repository?
examples/count_wires.rs (line 13)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let path = PathBuf::from(
6        std::env::args()
7            .nth(1)
8            .unwrap_or_else(|| "world.brz".to_string()),
9    );
10    let db = Brz::open(path)?.into_reader();
11
12    let mut grid_ids = vec![1];
13    for index in db.entity_chunk_index()? {
14        for e in db.entity_chunk(index)? {
15            if e.is_brick_grid() || e.is_microchip_grid() {
16                if let Some(id) = e.id {
17                    grid_ids.push(id);
18                }
19            }
20        }
21    }
22
23    let mut total_wires = 0u64;
24    let mut total_bricks = 0u64;
25    for &gid in &grid_ids {
26        let chunks = db.brick_chunk_index(gid)?;
27        for chunk in &chunks {
28            total_bricks += chunk.num_bricks as u64;
29            total_wires += chunk.num_wires as u64;
30        }
31    }
32
33    println!("grids: {}", grid_ids.len());
34    println!("bricks: {total_bricks}");
35    println!("wires: {total_wires}");
36    Ok(())
37}
More examples
Hide additional examples
examples/world_freeze_entities.rs (line 13)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let chunks = db.entity_chunk_index()?;
14    let entity_schema = db.entities_schema()?;
15    let global_data = db.global_data()?;
16    let mut chunk_files = vec![];
17
18    for index in chunks {
19        // Entity_chunk loads entities and their entity data
20        let entities = db.entity_chunk(index)?;
21
22        // Re-assemble the soa. using add_entity ensures the extra data is correctly handled
23        let mut soa = EntityChunkSoA::default();
24        for mut e in entities.into_iter() {
25            e.frozen = true;
26            soa.add_entity(&global_data, &e, e.id.unwrap() as u32);
27        }
28
29        chunk_files.push((
30            format!("{index}.mps"),
31            // EntityChunkSoA::to_bytes ensures the extra data is written after the SoA data
32            BrPendingFs::File(Some(soa.to_bytes(&entity_schema)?)),
33        ));
34    }
35
36    let patch = BrPendingFs::Root(vec![(
37        "World".to_owned(),
38        BrPendingFs::Folder(Some(vec![(
39            "0".to_string(),
40            BrPendingFs::Folder(Some(vec![(
41                "Entities".to_string(),
42                BrPendingFs::Folder(Some(vec![(
43                    "Chunks".to_string(),
44                    BrPendingFs::Folder(Some(chunk_files)),
45                )])),
46            )])),
47        )])),
48    )]);
49
50    // Use .to_pending_patch() if you want to update the same world
51    let pending = db.to_pending()?.with_patch(patch)?;
52    if dst.exists() {
53        std::fs::remove_file(&dst)?;
54    }
55    Brdb::new(&dst)?.write_pending("Freeze Entities", pending)?;
56
57    // Ensure entities can be read
58    let db = Brdb::open(dst)?.into_reader();
59    let chunks = db.entity_chunk_index()?;
60    for index in chunks {
61        let _ = db.entity_chunk(index)?;
62    }
63
64    Ok(())
65}
examples/read_world.rs (line 29)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/read_entities.rs (line 33)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    // Get global data to access entity type names and class names
19    let data = db.global_data()?;
20    println!("=== Entity Type Names ===");
21    for ((i, name), class) in data
22        .entity_type_names
23        .iter()
24        .enumerate()
25        .zip(data.entity_data_class_names.iter())
26    {
27        println!("{i}: {name} - {class}");
28    }
29    println!();
30
31    // Read all entity chunks
32    println!("=== Entity Chunks ===");
33    let entity_chunk_indices = db.entity_chunk_index()?;
34    println!("Found {} entity chunks", entity_chunk_indices.len());
35    println!();
36
37    let mut total_entities = 0;
38    for chunk_index in entity_chunk_indices {
39        println!("--- Chunk {} ---", chunk_index);
40        let entities = db.entity_chunk(chunk_index)?;
41
42        for (i, entity) in entities.iter().enumerate() {
43            total_entities += 1;
44            println!("  Entity {i}:");
45            println!("    Asset: {}", entity.asset);
46            println!("    ID: {:?}", entity.id);
47            println!("    Owner Index: {:?}", entity.owner_index);
48            println!("    Location: {:?}", entity.location);
49            println!("    Rotation: {:?}", entity.rotation);
50            println!("    Velocity: {:?}", entity.velocity);
51            println!("    Angular Velocity: {:?}", entity.angular_velocity);
52            println!("    Frozen: {:?}", entity.frozen);
53            println!("    Sleeping: {:?}", entity.sleeping);
54            println!();
55        }
56    }
57
58    println!("=== Summary ===");
59    println!("Total entities: {total_entities}");
60
61    // Also print the entity chunk SoA data
62    println!();
63    println!("=== Entity Chunk SoA Data ===");
64    for chunk_index in db.entity_chunk_index()? {
65        println!("--- Chunk {} (SoA) ---", chunk_index);
66        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
67
68        println!("  Type Counters: {:?}", soa.type_counters);
69        println!("  Number of entities with data: {}", entity_data.len());
70
71        for (i, data) in entity_data.iter().enumerate() {
72            if let Some(struct_data) = data {
73                println!("  Entity {i} struct: {struct_data}");
74            } else {
75                println!("  Entity {i}: None");
76            }
77        }
78        println!();
79    }
80
81    Ok(())
82}
examples/inspect_grids.rs (line 14)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from(
7        std::env::args()
8            .nth(1)
9            .unwrap_or_else(|| "world.brz".to_string()),
10    );
11    let db = Brz::open(path)?.into_reader();
12
13    let mut grid_ids = vec![1];
14    for index in db.entity_chunk_index()? {
15        for e in db.entity_chunk(index)? {
16            if e.is_brick_grid() || e.is_microchip_grid() {
17                if let Some(id) = e.id {
18                    grid_ids.push(id);
19                }
20            }
21        }
22    }
23
24    // For each grid, collect a fingerprint: (num_bricks, num_wires, num_chunks)
25    // to find grids that look identical.
26    let mut fingerprints: HashMap<(u64, u64, usize), Vec<usize>> = HashMap::new();
27    let mut total_bricks = 0u64;
28    let mut total_wires = 0u64;
29    let mut total_components = 0u64;
30
31    for &gid in &grid_ids {
32        let chunks = db.brick_chunk_index(gid)?;
33        let mut grid_bricks = 0u64;
34        let mut grid_wires = 0u64;
35        let mut grid_components = 0u64;
36        for chunk in &chunks {
37            grid_bricks += chunk.num_bricks as u64;
38            grid_wires += chunk.num_wires as u64;
39            grid_components += chunk.num_components as u64;
40        }
41        total_bricks += grid_bricks;
42        total_wires += grid_wires;
43        total_components += grid_components;
44
45        let fp = (grid_bricks, grid_wires, chunks.len());
46        fingerprints.entry(fp).or_default().push(gid);
47    }
48
49    println!("=== Grid Summary ===");
50    println!("total grids: {}", grid_ids.len());
51    println!("total bricks: {total_bricks}");
52    println!("total wires: {total_wires}");
53    println!("total components: {total_components}");
54    println!();
55
56    println!("=== Unique Grid Shapes ===");
57    let mut fps: Vec<_> = fingerprints.iter().collect();
58    fps.sort_by_key(|((b, _w, _), grids)| std::cmp::Reverse(*b * grids.len() as u64));
59
60    for ((bricks, wires, chunks), grids) in &fps {
61        let savings = if grids.len() > 1 {
62            format!(
63                " → {} could be deduplicated (save {} bricks, {} wires)",
64                grids.len() - 1,
65                bricks * (grids.len() as u64 - 1),
66                wires * (grids.len() as u64 - 1)
67            )
68        } else {
69            String::new()
70        };
71        println!(
72            "  {}×  ({} bricks, {} wires, {} chunks){}",
73            grids.len(),
74            bricks,
75            wires,
76            chunks,
77            savings
78        );
79    }
80
81    // Top 10 largest grids
82    println!();
83    println!("=== Top 10 Largest Grids ===");
84    let mut grid_sizes: Vec<(usize, u64, u64)> = Vec::new();
85    for &gid in &grid_ids {
86        let chunks = db.brick_chunk_index(gid)?;
87        let b: u64 = chunks.iter().map(|c| c.num_bricks as u64).sum();
88        let w: u64 = chunks.iter().map(|c| c.num_wires as u64).sum();
89        grid_sizes.push((gid, b, w));
90    }
91    grid_sizes.sort_by_key(|(_, b, _)| std::cmp::Reverse(*b));
92    for (gid, b, w) in grid_sizes.iter().take(10) {
93        println!("  grid {gid}: {b} bricks, {w} wires");
94    }
95
96    Ok(())
97}
examples/world_remove_shadows.rs (line 17)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let mut grid_ids = vec![1];
14
15    // Iterate all entity chunks to find dynamic brick grids...
16    // This could totally be a helper function
17    for index in db.entity_chunk_index()? {
18        for e in db.entity_chunk(index)? {
19            // Ensure the chunk is a dynamic brick grid
20            if !e.is_brick_grid() {
21                continue;
22            }
23            let Some(id) = e.id else {
24                continue;
25            };
26            grid_ids.push(id);
27        }
28    }
29
30    let component_schema = db.components_schema()?;
31    let mut grids_files = vec![];
32
33    // Iterate all grids (there can be bricks on entities)
34    for grid in &grid_ids {
35        let chunks = db.brick_chunk_index(*grid)?;
36        let mut chunk_files = vec![];
37        let mut num_grid_modified = 0;
38
39        // Iterate all chunks in the grid
40        for index in chunks {
41            let mut num_chunk_modified = 0;
42            if index.num_components == 0 {
43                println!("ignoring grid {grid} chunk {} with no components", *index);
44                continue;
45            }
46
47            // Iterate all the components in the chunk
48            let (mut soa, components) = db.component_chunk(*grid, *index)?;
49            for mut s in components {
50                // Disable the shadow casting property if it's present and true
51                if s.prop("bCastShadows")
52                    .is_ok_and(|v| v.as_brdb_bool().unwrap_or_default())
53                {
54                    println!(
55                        "grid {grid} chunk {} mutating component {}",
56                        *index,
57                        s.get_name()
58                    );
59                    s.set_prop("bCastShadows", BrdbValue::Bool(false))?;
60                    num_grid_modified += 1;
61                    num_chunk_modified += 1;
62                }
63
64                soa.unwritten_struct_data.push(Box::new(s));
65            }
66
67            if num_chunk_modified == 0 {
68                continue;
69            }
70
71            chunk_files.push((
72                format!("{}.mps", *index),
73                // ComponentChunkSoA::to_bytes ensures the extra data is written after the SoA data
74                BrPendingFs::File(Some(soa.to_bytes(&component_schema)?)),
75            ));
76        }
77
78        if num_grid_modified == 0 {
79            println!("grid {grid} has no shadow-casting components, skipping");
80            continue;
81        } else {
82            println!(
83                "grid {grid} has {num_grid_modified} shadow-casting components in {} files",
84                chunk_files.len()
85            );
86        }
87
88        grids_files.push((
89            grid.to_string(),
90            BrPendingFs::Folder(Some(vec![(
91                "Components".to_string(),
92                BrPendingFs::Folder(Some(chunk_files)),
93            )])),
94        ))
95    }
96
97    let patch = BrPendingFs::Root(vec![(
98        "World".to_owned(),
99        BrPendingFs::Folder(Some(vec![(
100            "0".to_string(),
101            BrPendingFs::Folder(Some(vec![(
102                "Bricks".to_string(),
103                BrPendingFs::Folder(Some(vec![(
104                    "Grids".to_string(),
105                    BrPendingFs::Folder(Some(grids_files)),
106                )])),
107            )])),
108        )])),
109    )]);
110
111    // Use .to_pending_patch() if you want to update the same world
112    let pending = db.to_pending()?.with_patch(patch)?;
113    if dst.exists() {
114        std::fs::remove_file(&dst)?;
115    }
116    Brdb::new(&dst)?.write_pending("Disable Shadow Casting", pending)?;
117
118    // Ensure all the components can be read
119    let db = Brdb::open(dst)?.into_reader();
120    for grid in grid_ids {
121        let chunks = db.brick_chunk_index(grid)?;
122        for index in chunks {
123            if index.num_components == 0 {
124                continue;
125            }
126            let (_soa, _components) = db.component_chunk(grid, *index)?;
127        }
128    }
129
130    Ok(())
131}
Source

pub fn entity_chunk_index_soa(&self) -> Result<EntityChunkIndexSoA, BrError>
where T: BrFsReader,

Read the entity chunk indices

Source

pub fn entity_chunk(&self, chunk: ChunkIndex) -> Result<Vec<Entity>, BrError>
where T: BrFsReader,

Examples found in repository?
examples/count_wires.rs (line 14)
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    let path = PathBuf::from(
6        std::env::args()
7            .nth(1)
8            .unwrap_or_else(|| "world.brz".to_string()),
9    );
10    let db = Brz::open(path)?.into_reader();
11
12    let mut grid_ids = vec![1];
13    for index in db.entity_chunk_index()? {
14        for e in db.entity_chunk(index)? {
15            if e.is_brick_grid() || e.is_microchip_grid() {
16                if let Some(id) = e.id {
17                    grid_ids.push(id);
18                }
19            }
20        }
21    }
22
23    let mut total_wires = 0u64;
24    let mut total_bricks = 0u64;
25    for &gid in &grid_ids {
26        let chunks = db.brick_chunk_index(gid)?;
27        for chunk in &chunks {
28            total_bricks += chunk.num_bricks as u64;
29            total_wires += chunk.num_wires as u64;
30        }
31    }
32
33    println!("grids: {}", grid_ids.len());
34    println!("bricks: {total_bricks}");
35    println!("wires: {total_wires}");
36    Ok(())
37}
More examples
Hide additional examples
examples/world_freeze_entities.rs (line 20)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let chunks = db.entity_chunk_index()?;
14    let entity_schema = db.entities_schema()?;
15    let global_data = db.global_data()?;
16    let mut chunk_files = vec![];
17
18    for index in chunks {
19        // Entity_chunk loads entities and their entity data
20        let entities = db.entity_chunk(index)?;
21
22        // Re-assemble the soa. using add_entity ensures the extra data is correctly handled
23        let mut soa = EntityChunkSoA::default();
24        for mut e in entities.into_iter() {
25            e.frozen = true;
26            soa.add_entity(&global_data, &e, e.id.unwrap() as u32);
27        }
28
29        chunk_files.push((
30            format!("{index}.mps"),
31            // EntityChunkSoA::to_bytes ensures the extra data is written after the SoA data
32            BrPendingFs::File(Some(soa.to_bytes(&entity_schema)?)),
33        ));
34    }
35
36    let patch = BrPendingFs::Root(vec![(
37        "World".to_owned(),
38        BrPendingFs::Folder(Some(vec![(
39            "0".to_string(),
40            BrPendingFs::Folder(Some(vec![(
41                "Entities".to_string(),
42                BrPendingFs::Folder(Some(vec![(
43                    "Chunks".to_string(),
44                    BrPendingFs::Folder(Some(chunk_files)),
45                )])),
46            )])),
47        )])),
48    )]);
49
50    // Use .to_pending_patch() if you want to update the same world
51    let pending = db.to_pending()?.with_patch(patch)?;
52    if dst.exists() {
53        std::fs::remove_file(&dst)?;
54    }
55    Brdb::new(&dst)?.write_pending("Freeze Entities", pending)?;
56
57    // Ensure entities can be read
58    let db = Brdb::open(dst)?.into_reader();
59    let chunks = db.entity_chunk_index()?;
60    for index in chunks {
61        let _ = db.entity_chunk(index)?;
62    }
63
64    Ok(())
65}
examples/read_world.rs (line 30)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    let data = db.global_data()?;
19    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
20    println!("Wire ports: {:?}", data.component_wire_port_names);
21    println!("Component types: {:?}", data.component_type_names);
22    println!("Component structs: {:?}", data.component_data_struct_names);
23    println!("Component schemas: {}", db.components_schema()?);
24
25    let mut grid_ids = vec![1];
26
27    // Iterate all entity chunks to find dynamic brick grids...
28    // This could totally be a helper function
29    for index in db.entity_chunk_index()? {
30        for e in db.entity_chunk(index)? {
31            // Ensure the chunk is a dynamic brick grid
32            if !e.is_brick_grid() {
33                continue;
34            }
35            let Some(id) = e.id else {
36                continue;
37            };
38            grid_ids.push(id);
39        }
40    }
41
42    for gid in grid_ids {
43        println!("Reading grid {gid}");
44        let chunks = db.brick_chunk_index(gid)?;
45        println!("Brick chunks: {chunks:?}");
46        for chunk in chunks {
47            let soa = db.brick_chunk_soa(gid, chunk.index)?;
48            println!("Brick Soa {chunk}: {soa:?}");
49            if chunk.num_components > 0 {
50                let (_soa, components) = db.component_chunk_soa(gid, chunk.index)?;
51                // println!("Components soa: {soa}");
52                for c in components {
53                    println!("Component: {c}");
54                }
55            }
56            if chunk.num_wires > 0 {
57                let soa = db.wire_chunk_soa(gid, chunk.index)?;
58                println!("Wires soa: {soa}");
59            }
60        }
61    }
62
63    println!("Files: {}", db.get_fs()?.render());
64
65    Ok(())
66}
examples/read_entities.rs (line 40)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    // Get global data to access entity type names and class names
19    let data = db.global_data()?;
20    println!("=== Entity Type Names ===");
21    for ((i, name), class) in data
22        .entity_type_names
23        .iter()
24        .enumerate()
25        .zip(data.entity_data_class_names.iter())
26    {
27        println!("{i}: {name} - {class}");
28    }
29    println!();
30
31    // Read all entity chunks
32    println!("=== Entity Chunks ===");
33    let entity_chunk_indices = db.entity_chunk_index()?;
34    println!("Found {} entity chunks", entity_chunk_indices.len());
35    println!();
36
37    let mut total_entities = 0;
38    for chunk_index in entity_chunk_indices {
39        println!("--- Chunk {} ---", chunk_index);
40        let entities = db.entity_chunk(chunk_index)?;
41
42        for (i, entity) in entities.iter().enumerate() {
43            total_entities += 1;
44            println!("  Entity {i}:");
45            println!("    Asset: {}", entity.asset);
46            println!("    ID: {:?}", entity.id);
47            println!("    Owner Index: {:?}", entity.owner_index);
48            println!("    Location: {:?}", entity.location);
49            println!("    Rotation: {:?}", entity.rotation);
50            println!("    Velocity: {:?}", entity.velocity);
51            println!("    Angular Velocity: {:?}", entity.angular_velocity);
52            println!("    Frozen: {:?}", entity.frozen);
53            println!("    Sleeping: {:?}", entity.sleeping);
54            println!();
55        }
56    }
57
58    println!("=== Summary ===");
59    println!("Total entities: {total_entities}");
60
61    // Also print the entity chunk SoA data
62    println!();
63    println!("=== Entity Chunk SoA Data ===");
64    for chunk_index in db.entity_chunk_index()? {
65        println!("--- Chunk {} (SoA) ---", chunk_index);
66        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
67
68        println!("  Type Counters: {:?}", soa.type_counters);
69        println!("  Number of entities with data: {}", entity_data.len());
70
71        for (i, data) in entity_data.iter().enumerate() {
72            if let Some(struct_data) = data {
73                println!("  Entity {i} struct: {struct_data}");
74            } else {
75                println!("  Entity {i}: None");
76            }
77        }
78        println!();
79    }
80
81    Ok(())
82}
examples/inspect_grids.rs (line 15)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from(
7        std::env::args()
8            .nth(1)
9            .unwrap_or_else(|| "world.brz".to_string()),
10    );
11    let db = Brz::open(path)?.into_reader();
12
13    let mut grid_ids = vec![1];
14    for index in db.entity_chunk_index()? {
15        for e in db.entity_chunk(index)? {
16            if e.is_brick_grid() || e.is_microchip_grid() {
17                if let Some(id) = e.id {
18                    grid_ids.push(id);
19                }
20            }
21        }
22    }
23
24    // For each grid, collect a fingerprint: (num_bricks, num_wires, num_chunks)
25    // to find grids that look identical.
26    let mut fingerprints: HashMap<(u64, u64, usize), Vec<usize>> = HashMap::new();
27    let mut total_bricks = 0u64;
28    let mut total_wires = 0u64;
29    let mut total_components = 0u64;
30
31    for &gid in &grid_ids {
32        let chunks = db.brick_chunk_index(gid)?;
33        let mut grid_bricks = 0u64;
34        let mut grid_wires = 0u64;
35        let mut grid_components = 0u64;
36        for chunk in &chunks {
37            grid_bricks += chunk.num_bricks as u64;
38            grid_wires += chunk.num_wires as u64;
39            grid_components += chunk.num_components as u64;
40        }
41        total_bricks += grid_bricks;
42        total_wires += grid_wires;
43        total_components += grid_components;
44
45        let fp = (grid_bricks, grid_wires, chunks.len());
46        fingerprints.entry(fp).or_default().push(gid);
47    }
48
49    println!("=== Grid Summary ===");
50    println!("total grids: {}", grid_ids.len());
51    println!("total bricks: {total_bricks}");
52    println!("total wires: {total_wires}");
53    println!("total components: {total_components}");
54    println!();
55
56    println!("=== Unique Grid Shapes ===");
57    let mut fps: Vec<_> = fingerprints.iter().collect();
58    fps.sort_by_key(|((b, _w, _), grids)| std::cmp::Reverse(*b * grids.len() as u64));
59
60    for ((bricks, wires, chunks), grids) in &fps {
61        let savings = if grids.len() > 1 {
62            format!(
63                " → {} could be deduplicated (save {} bricks, {} wires)",
64                grids.len() - 1,
65                bricks * (grids.len() as u64 - 1),
66                wires * (grids.len() as u64 - 1)
67            )
68        } else {
69            String::new()
70        };
71        println!(
72            "  {}×  ({} bricks, {} wires, {} chunks){}",
73            grids.len(),
74            bricks,
75            wires,
76            chunks,
77            savings
78        );
79    }
80
81    // Top 10 largest grids
82    println!();
83    println!("=== Top 10 Largest Grids ===");
84    let mut grid_sizes: Vec<(usize, u64, u64)> = Vec::new();
85    for &gid in &grid_ids {
86        let chunks = db.brick_chunk_index(gid)?;
87        let b: u64 = chunks.iter().map(|c| c.num_bricks as u64).sum();
88        let w: u64 = chunks.iter().map(|c| c.num_wires as u64).sum();
89        grid_sizes.push((gid, b, w));
90    }
91    grid_sizes.sort_by_key(|(_, b, _)| std::cmp::Reverse(*b));
92    for (gid, b, w) in grid_sizes.iter().take(10) {
93        println!("  grid {gid}: {b} bricks, {w} wires");
94    }
95
96    Ok(())
97}
examples/world_remove_shadows.rs (line 18)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let src = PathBuf::from("world.brdb");
7    let dst = PathBuf::from("world_patched.brdb");
8
9    assert!(src.exists());
10
11    let db = Brdb::open(src)?.into_reader();
12
13    let mut grid_ids = vec![1];
14
15    // Iterate all entity chunks to find dynamic brick grids...
16    // This could totally be a helper function
17    for index in db.entity_chunk_index()? {
18        for e in db.entity_chunk(index)? {
19            // Ensure the chunk is a dynamic brick grid
20            if !e.is_brick_grid() {
21                continue;
22            }
23            let Some(id) = e.id else {
24                continue;
25            };
26            grid_ids.push(id);
27        }
28    }
29
30    let component_schema = db.components_schema()?;
31    let mut grids_files = vec![];
32
33    // Iterate all grids (there can be bricks on entities)
34    for grid in &grid_ids {
35        let chunks = db.brick_chunk_index(*grid)?;
36        let mut chunk_files = vec![];
37        let mut num_grid_modified = 0;
38
39        // Iterate all chunks in the grid
40        for index in chunks {
41            let mut num_chunk_modified = 0;
42            if index.num_components == 0 {
43                println!("ignoring grid {grid} chunk {} with no components", *index);
44                continue;
45            }
46
47            // Iterate all the components in the chunk
48            let (mut soa, components) = db.component_chunk(*grid, *index)?;
49            for mut s in components {
50                // Disable the shadow casting property if it's present and true
51                if s.prop("bCastShadows")
52                    .is_ok_and(|v| v.as_brdb_bool().unwrap_or_default())
53                {
54                    println!(
55                        "grid {grid} chunk {} mutating component {}",
56                        *index,
57                        s.get_name()
58                    );
59                    s.set_prop("bCastShadows", BrdbValue::Bool(false))?;
60                    num_grid_modified += 1;
61                    num_chunk_modified += 1;
62                }
63
64                soa.unwritten_struct_data.push(Box::new(s));
65            }
66
67            if num_chunk_modified == 0 {
68                continue;
69            }
70
71            chunk_files.push((
72                format!("{}.mps", *index),
73                // ComponentChunkSoA::to_bytes ensures the extra data is written after the SoA data
74                BrPendingFs::File(Some(soa.to_bytes(&component_schema)?)),
75            ));
76        }
77
78        if num_grid_modified == 0 {
79            println!("grid {grid} has no shadow-casting components, skipping");
80            continue;
81        } else {
82            println!(
83                "grid {grid} has {num_grid_modified} shadow-casting components in {} files",
84                chunk_files.len()
85            );
86        }
87
88        grids_files.push((
89            grid.to_string(),
90            BrPendingFs::Folder(Some(vec![(
91                "Components".to_string(),
92                BrPendingFs::Folder(Some(chunk_files)),
93            )])),
94        ))
95    }
96
97    let patch = BrPendingFs::Root(vec![(
98        "World".to_owned(),
99        BrPendingFs::Folder(Some(vec![(
100            "0".to_string(),
101            BrPendingFs::Folder(Some(vec![(
102                "Bricks".to_string(),
103                BrPendingFs::Folder(Some(vec![(
104                    "Grids".to_string(),
105                    BrPendingFs::Folder(Some(grids_files)),
106                )])),
107            )])),
108        )])),
109    )]);
110
111    // Use .to_pending_patch() if you want to update the same world
112    let pending = db.to_pending()?.with_patch(patch)?;
113    if dst.exists() {
114        std::fs::remove_file(&dst)?;
115    }
116    Brdb::new(&dst)?.write_pending("Disable Shadow Casting", pending)?;
117
118    // Ensure all the components can be read
119    let db = Brdb::open(dst)?.into_reader();
120    for grid in grid_ids {
121        let chunks = db.brick_chunk_index(grid)?;
122        for index in chunks {
123            if index.num_components == 0 {
124                continue;
125            }
126            let (_soa, _components) = db.component_chunk(grid, *index)?;
127        }
128    }
129
130    Ok(())
131}
Source

pub fn entity_chunk_soa( &self, chunk: ChunkIndex, ) -> Result<(EntityChunkSoA, Vec<Option<BrdbStruct>>), BrError>
where T: BrFsReader,

Examples found in repository?
examples/read_entities.rs (line 66)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    // world file from argv
7    let filename = std::env::args()
8        .nth(1)
9        .unwrap_or_else(|| "world.brdb".to_string());
10    let path = PathBuf::from(filename);
11    if !path.exists() {
12        eprintln!("File does not exist: {}", path.display());
13        std::process::exit(1);
14    }
15
16    let db = Brdb::open(path)?.into_reader();
17
18    // Get global data to access entity type names and class names
19    let data = db.global_data()?;
20    println!("=== Entity Type Names ===");
21    for ((i, name), class) in data
22        .entity_type_names
23        .iter()
24        .enumerate()
25        .zip(data.entity_data_class_names.iter())
26    {
27        println!("{i}: {name} - {class}");
28    }
29    println!();
30
31    // Read all entity chunks
32    println!("=== Entity Chunks ===");
33    let entity_chunk_indices = db.entity_chunk_index()?;
34    println!("Found {} entity chunks", entity_chunk_indices.len());
35    println!();
36
37    let mut total_entities = 0;
38    for chunk_index in entity_chunk_indices {
39        println!("--- Chunk {} ---", chunk_index);
40        let entities = db.entity_chunk(chunk_index)?;
41
42        for (i, entity) in entities.iter().enumerate() {
43            total_entities += 1;
44            println!("  Entity {i}:");
45            println!("    Asset: {}", entity.asset);
46            println!("    ID: {:?}", entity.id);
47            println!("    Owner Index: {:?}", entity.owner_index);
48            println!("    Location: {:?}", entity.location);
49            println!("    Rotation: {:?}", entity.rotation);
50            println!("    Velocity: {:?}", entity.velocity);
51            println!("    Angular Velocity: {:?}", entity.angular_velocity);
52            println!("    Frozen: {:?}", entity.frozen);
53            println!("    Sleeping: {:?}", entity.sleeping);
54            println!();
55        }
56    }
57
58    println!("=== Summary ===");
59    println!("Total entities: {total_entities}");
60
61    // Also print the entity chunk SoA data
62    println!();
63    println!("=== Entity Chunk SoA Data ===");
64    for chunk_index in db.entity_chunk_index()? {
65        println!("--- Chunk {} (SoA) ---", chunk_index);
66        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
67
68        println!("  Type Counters: {:?}", soa.type_counters);
69        println!("  Number of entities with data: {}", entity_data.len());
70
71        for (i, data) in entity_data.iter().enumerate() {
72            if let Some(struct_data) = data {
73                println!("  Entity {i} struct: {struct_data}");
74            } else {
75                println!("  Entity {i}: None");
76            }
77        }
78        println!();
79    }
80
81    Ok(())
82}
More examples
Hide additional examples
examples/dump_fixture.rs (line 142)
11fn run<T: BrFsReader>(db: &BrReader<T>) -> Result<(), Box<dyn std::error::Error>> {
12    let data = db.global_data()?;
13    println!("Basic Brick assets: {:?}", data.basic_brick_asset_names);
14    println!("Procedural Brick assets: {:?}", data.procedural_brick_asset_names);
15    // register_all_components() embeds the FULL catalog (hundreds of wire
16    // ports/component types), so only print counts for those — the fixture's
17    // OWN types/ports are visible per-brick below via the type-name lookups.
18    println!(
19        "Wire port count: {} (registered catalog)",
20        data.component_wire_port_names.len()
21    );
22    println!(
23        "Component type count: {} (registered catalog)",
24        data.component_type_names.len()
25    );
26    println!("Entity types: {:?}", data.entity_type_names);
27    println!("Entity classes: {:?}", data.entity_data_class_names);
28
29    // Probe grid ids 1.. until one is missing (grid 1 is always the main
30    // grid; higher ids are sub-grids / microchip inner grids).
31    for gid in 1..32 {
32        let chunks = match db.brick_chunk_index(gid) {
33            Ok(c) => c,
34            Err(_) => break,
35        };
36        println!("=== grid {gid} ===");
37        println!("Brick chunks: {chunks:?}");
38        for chunk in &chunks {
39            let soa = db.brick_chunk_soa(gid, chunk.index)?;
40            println!("Brick soa: {soa:?}");
41            let asset_names: Vec<String> = soa
42                .brick_type_indices
43                .iter()
44                .map(|&t| {
45                    if (t as usize) < soa.procedural_brick_starting_index as usize {
46                        data.basic_brick_asset_names
47                            .get_index(t as usize)
48                            .cloned()
49                            .unwrap_or_default()
50                    } else {
51                        "<procedural>".to_string()
52                    }
53                })
54                .collect();
55            println!("Brick asset names (by index in chunk): {asset_names:?}");
56
57            if chunk.num_components > 0 {
58                let (soa, components) = db.component_chunk_soa(gid, chunk.index)?;
59                let type_names: Vec<String> = soa
60                    .component_type_counters
61                    .iter()
62                    .flat_map(|c| {
63                        let name = data
64                            .component_type_names
65                            .get_index(c.type_index as usize)
66                            .cloned()
67                            .unwrap_or_default();
68                        (0..c.num_instances).map(move |_| name.clone())
69                    })
70                    .collect();
71                println!(
72                    "Component chunk soa: component_brick_indices={:?} microchip_brick_indices={:?} microchip_brick_grid_references={:?}",
73                    soa.component_brick_indices,
74                    soa.microchip_brick_indices,
75                    soa.microchip_brick_grid_references
76                );
77                println!("Component type names (parallel to ComponentBrickIndices): {type_names:?}");
78                for c in components {
79                    println!("Component: {c}");
80                }
81            }
82            if chunk.num_wires > 0 {
83                let raw = db.wire_chunk_soa(gid, chunk.index)?;
84                println!("Wire chunk soa (raw struct): {raw}");
85                let value = raw.to_value();
86                let soa: WireChunkSoA = (&value).try_into()?;
87                let port_name = |i: u16| {
88                    data.component_wire_port_names
89                        .get_index(i as usize)
90                        .cloned()
91                        .unwrap_or_default()
92                };
93                let type_name = |i: u16| {
94                    data.component_type_names
95                        .get_index(i as usize)
96                        .cloned()
97                        .unwrap_or_default()
98                };
99                for s in &soa.local_wire_sources {
100                    println!(
101                        "  local source: brick_in_chunk={} type={} port={}",
102                        s.brick_index_in_chunk,
103                        type_name(s.component_type_index),
104                        port_name(s.port_index)
105                    );
106                }
107                for t in &soa.local_wire_targets {
108                    println!(
109                        "  local target: brick_in_chunk={} type={} port={}",
110                        t.brick_index_in_chunk,
111                        type_name(t.component_type_index),
112                        port_name(t.port_index)
113                    );
114                }
115                for s in &soa.remote_wire_sources {
116                    println!(
117                        "  remote source: grid_persistent_index={} chunk={} brick_in_chunk={} type={} port={}",
118                        s.grid_persistent_index,
119                        s.chunk_index,
120                        s.brick_index_in_chunk,
121                        type_name(s.component_type_index),
122                        port_name(s.port_index)
123                    );
124                }
125                for t in &soa.remote_wire_targets {
126                    println!(
127                        "  remote target: brick_in_chunk={} type={} port={}",
128                        t.brick_index_in_chunk,
129                        type_name(t.component_type_index),
130                        port_name(t.port_index)
131                    );
132                }
133            }
134        }
135    }
136
137    // Entity chunks (present whenever the world has any grids/entities).
138    let entity_chunk_indices = db.entity_chunk_index()?;
139    println!("=== entities ===");
140    println!("Entity chunk indices: {entity_chunk_indices:?}");
141    for chunk_index in entity_chunk_indices {
142        let (soa, entity_data) = db.entity_chunk_soa(chunk_index)?;
143        println!("--- Chunk {chunk_index} (SoA) ---");
144        println!("Type counters: {:?}", soa.type_counters);
145        let type_names: Vec<String> = soa
146            .type_counters
147            .iter()
148            .flat_map(|c| {
149                let name = data
150                    .entity_type_names
151                    .get_index(c.type_index as usize)
152                    .cloned()
153                    .unwrap_or_default();
154                (0..c.num_entities).map(move |_| name.clone())
155            })
156            .collect();
157        println!("Entity type names (parallel to PersistentIndices): {type_names:?}");
158        println!("Persistent indices: {:?}", soa.persistent_indices);
159        println!("Locations: {:?}", soa.locations);
160        println!("Rotations: {:?}", soa.rotations);
161        println!("Physics locked (frozen): {:?}", soa.physics_locked_flags);
162        println!("Physics sleeping: {:?}", soa.physics_sleeping_flags);
163        for (i, data) in entity_data.iter().enumerate() {
164            match data {
165                Some(struct_data) => println!("  Entity {i} struct: {struct_data}"),
166                None => println!("  Entity {i}: None"),
167            }
168        }
169    }
170
171    println!("Files: {}", db.get_fs()?.render());
172
173    Ok(())
174}

Trait Implementations§

Source§

impl<T> Deref for BrReader<T>

Source§

type Target = T

The resulting type after dereferencing.
Source§

fn deref(&self) -> &Self::Target

Dereferences the value.

Auto Trait Implementations§

§

impl<T> !Freeze for BrReader<T>

§

impl<T> RefUnwindSafe for BrReader<T>
where T: RefUnwindSafe,

§

impl<T> Send for BrReader<T>
where T: Send,

§

impl<T> Sync for BrReader<T>
where T: Sync,

§

impl<T> Unpin for BrReader<T>
where T: Unpin,

§

impl<T> UnsafeUnpin for BrReader<T>
where T: UnsafeUnpin,

§

impl<T> UnwindSafe for BrReader<T>
where T: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<P, T> Receiver for P
where P: Deref<Target = T> + ?Sized, T: ?Sized,

Source§

type Target = T

🔬This is a nightly-only experimental API. (arbitrary_self_types)
The target type on which the method may be called.
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.