Skip to main content

World

Struct World 

Source
pub struct World {
    pub meta: WorldMeta,
    pub owners: IndexMap<Guid, Owner>,
    pub bricks: Vec<Brick>,
    pub grids: Vec<(Entity, Vec<Brick>)>,
    pub wires: Vec<WireConnection>,
    pub entities: Vec<Entity>,
    pub microchip_links: Vec<(usize, usize)>,
    pub prefabs: IndexMap<String, Vec<u8>>,
    pub global_data: BrdbSchemaGlobalData,
    pub component_schema: BrdbSchema,
    pub entity_schema: BrdbSchema,
    pub schema_format: BrdbSchemaFormat,
}

Fields§

§meta: WorldMeta§owners: IndexMap<Guid, Owner>§bricks: Vec<Brick>

Bricks on the main grid

§grids: Vec<(Entity, Vec<Brick>)>

Non-main grids require an entity to be created for them

§wires: Vec<WireConnection>§entities: Vec<Entity>§microchip_links: Vec<(usize, usize)>

Per-microchip linkage pairs: (brick_id, entity_id) where the brick is the outer microchip shell and the entity is the inner grid.

§prefabs: IndexMap<String, Vec<u8>>

Embedded prefab archives (the root Prefabs/ folder), keyed by root-relative path (Prefabs/Uploads/<BLAKE3>.brz) with raw .brz bytes as values. Populate via World::add_prefab; the returned path is what a Prefab component property references.

The game requires the Prefabs/Uploads/<BLAKE3>.brz naming — it crashes loading a bundle whose embedded prefab has any other filename. Use World::add_prefab rather than inserting a custom key here.

§global_data: BrdbSchemaGlobalData§component_schema: BrdbSchema§entity_schema: BrdbSchema§schema_format: BrdbSchemaFormat

The save format this world is written in.

BrdbSchemaFormat::Latest (the default) writes every schema in the map form, as the game writes them.

BrdbSchemaFormat::Auto writes each .schema in the container it needs: the map form for schemas with a types table or dynamic containers (the component schema), the array form otherwise. Every current game build reads both, but a world written this way without components has an EA3 component schema, so crate::migrate::needs_migration reports it as an EA3 save.

Writing EA3 worlds is not supported: World::to_unsaved fails with BrdbWorldError::Ea3WriteUnsupported.

Implementations§

Source§

impl World

Source

pub fn new() -> Self

Examples found in repository?
examples/write_fixtures.rs (line 26)
24fn brick_world() -> World {
25    // Mirror of examples/write_brz.rs — the historical example_brick world.
26    let mut world = World::new();
27    world.meta.bundle.description = "Example World".to_string();
28    world.bricks.push(Brick {
29        position: (0, 0, 6).into(),
30        color: (255, 0, 0).into(),
31        ..Default::default()
32    });
33    world
34}
35
36fn features_world() -> World {
37    // Single chunk (all coords in [0, 2048)): registries, owners, procedural
38    // size run-length grouping (new/extend/reuse), a basic asset, collision
39    // and visibility variants, orientations, material intensity.
40    let mut world = World::new();
41    world.meta.bundle.description = "Feature fixture".to_string();
42
43    let alice = Guid::from_uuid(uuid::Uuid::parse_str(ALICE_UUID).unwrap());
44    let bob = Guid::from_uuid(uuid::Uuid::parse_str(BOB_UUID).unwrap());
45    world.owners.insert(
46        alice,
47        Owner {
48            user_id: alice,
49            user_name: "alice".to_string(),
50            display_name: "Alice".to_string(),
51        },
52    );
53    world.owners.insert(
54        bob,
55        Owner {
56            user_id: bob,
57            user_name: "bob".to_string(),
58            display_name: "Bob".to_string(),
59        },
60    );
61
62    let tile = |size: (u16, u16, u16)| BrickType::Procedural {
63        asset: assets::bricks::PB_DEFAULT_TILE, // "PB_DefaultTile"
64        size: BrickSize {
65            x: size.0,
66            y: size.1,
67            z: size.2,
68        },
69    };
70
71    // 1: default brick (PB_DefaultBrick 5x5x6, plastic, intensity 5) — new size slot
72    world.bricks.push(Brick {
73        position: (0, 0, 6).into(),
74        color: (255, 0, 0).into(),
75        owner_index: Some(1),
76        ..Default::default()
77    });
78    // 2: tile 10x10x2, metallic, intensity 7, XPositive/Deg90 — new counter entry
79    world.bricks.push(Brick {
80        asset: tile((10, 10, 2)),
81        position: (20, 0, 2).into(),
82        color: (0, 255, 0).into(),
83        owner_index: Some(1),
84        material: assets::materials::METALLIC, // "BMC_Metallic"
85        material_intensity: 7,
86        direction: Direction::XPositive,
87        rotation: Rotation::Deg90,
88        ..Default::default()
89    });
90    // 3: same tile size — size_index_map reuse
91    world.bricks.push(Brick {
92        asset: tile((10, 10, 2)),
93        position: (40, 0, 2).into(),
94        color: (0, 0, 255).into(),
95        owner_index: Some(2),
96        ..Default::default()
97    });
98    // 4: tile 20x20x2 — extends the tail counter (same asset, new size)
99    world.bricks.push(Brick {
100        asset: tile((20, 20, 2)),
101        position: (80, 0, 2).into(),
102        color: (255, 255, 0).into(),
103        owner_index: Some(2),
104        ..Default::default()
105    });
106    // 5: default brick again — reuses slot from brick 1 (map hit after other asset)
107    world.bricks.push(Brick {
108        position: (100, 0, 6).into(),
109        color: (255, 255, 255).into(),
110        owner_index: Some(1),
111        ..Default::default()
112    });
113    // 6: BASIC asset, PUBLIC owner, glow, partial collision, YNegative/Deg180
114    world.bricks.push(Brick {
115        asset: assets::bricks::B_2X2_OVERHANG, // "B_2x2_Overhang"
116        position: (200, 0, 10).into(),
117        color: (128, 64, 32).into(),
118        material: assets::materials::GLOW, // "BMC_Glow"
119        material_intensity: 3,
120        direction: Direction::YNegative,
121        rotation: Rotation::Deg180,
122        collision: Collision {
123            player: false,
124            ..Default::default()
125        },
126        ..Default::default()
127    });
128    // 7: invisible, all-collision-off, tiny proc brick
129    world.bricks.push(Brick {
130        asset: BrickType::Procedural {
131            asset: assets::bricks::PB_DEFAULT_BRICK,
132            size: BrickSize { x: 2, y: 2, z: 2 },
133        },
134        position: (300, 0, 2).into(),
135        color: (10, 20, 30).into(),
136        owner_index: Some(1),
137        visible: false,
138        collision: Collision {
139            player: false,
140            weapon: false,
141            interact: false,
142            physics: false,
143            ..Default::default()
144        },
145        ..Default::default()
146    });
147    world
148}
149
150fn chunks_world() -> World {
151    // Multi-chunk: euclidean chunking with negative coords, plus chunks
152    // 0_0_0 and 1_0_0 carry byte-identical SoA payloads → blob dedup.
153    // NOTE: multi-chunk Rust output has nondeterministic FILE ORDER
154    // (HashMap iteration), so this fixture is hashes-gate only — never
155    // byte-compare its container.
156    let mut world = World::new();
157    world.meta.bundle.description = "Chunk fixture".to_string();
158    for (pos, color) in [
159        ((0, 0, 0), (1, 2, 3)),
160        ((-1, -1, -1), (4, 5, 6)),
161        ((2048, 0, 0), (1, 2, 3)), // same rel pos + color as brick 1
162        ((-2048, 4096, 10), (10, 11, 12)),
163        ((500, 500, 500), (42, 42, 42)),
164        ((2548, 500, 500), (42, 42, 42)), // same rel pos + color as brick 5
165    ] {
166        world.bricks.push(Brick {
167            position: pos.into(),
168            color: color.into(),
169            ..Default::default()
170        });
171    }
172    world
173}
174
175fn wires_world() -> World {
176    // Mirror of examples/write_wire.rs (single grid, single chunk — fully
177    // deterministic), extended to 3 bricks/2 wires: a boolean NOT gate feeds
178    // one input of an AND gate, whose output feeds a rerouter.
179    let mut world = World::new();
180    world.register_all_components();
181    world.meta.bundle.description = "Wire fixture".to_string();
182
183    let (a, a_id) = Brick {
184        position: (30, 0, 1).into(),
185        color: (255, 0, 0).into(),
186        asset: assets::bricks::B_REROUTE,
187        ..Default::default()
188    }
189    .with_component(assets::components::Rerouter)
190    .with_id_split();
191    let (b, b_id) = Brick {
192        position: (15, 0, 1).into(),
193        color: (0, 255, 0).into(),
194        asset: assets::components::LogicGate::BoolAnd.brick(),
195        ..Default::default()
196    }
197    .with_component(assets::components::LogicGate::BoolAnd.component())
198    .with_id_split();
199    let (c, c_id) = Brick {
200        position: (0, 0, 1).into(),
201        color: (0, 0, 255).into(),
202        asset: assets::components::LogicGate::BoolNot.brick(),
203        ..Default::default()
204    }
205    .with_component(assets::components::LogicGate::BoolNot.component())
206    .with_id_split();
207
208    world.add_bricks([a, b, c]);
209    // Wire 1: NOT.output -> AND.inputA
210    world.add_wire_connection(
211        assets::components::LogicGate::BoolNot.output_of(c_id),
212        assets::components::LogicGate::BoolAnd.input_a_of(b_id),
213    );
214    // Wire 2: AND.output -> Rerouter.input
215    world.add_wire_connection(
216        assets::components::LogicGate::BoolAnd.output_of(b_id),
217        assets::components::Rerouter::input_of(a_id),
218    );
219
220    world
221}
222
223fn components_world() -> World {
224    // Single grid, single chunk (all positions < 2048) — fully deterministic.
225    // register_all_components() embeds the full component catalog so every
226    // type below (light/interact/buffer/expr) resolves; each
227    // component below carries non-default property values, and #4/#5 exercise
228    // a WireValue-typed property (BufferTicks' Input/Output, and the Blend
229    // gate's inputs).
230    let mut world = World::new();
231    world.register_all_components();
232    world.meta.bundle.description = "Component fixture".to_string();
233
234    // 1: Point light — non-default brightness/radius/color, decoupled from
235    // brick color (bUseBrickColor: false).
236    world.bricks.push(
237        Brick {
238            position: (0, 0, 6).into(),
239            color: (255, 255, 255).into(),
240            ..Default::default()
241        }
242        .with_component(
243            assets::LiteralComponent::new("Component_PointLight").with_data([
244                ("bMatchBrickShape", Box::new(false) as Box<dyn AsBrdbValue>),
245                ("bEnabled", Box::new(true)),
246                ("Brightness", Box::new(500.0f32)),
247                ("Radius", Box::new(800.0f32)),
248                (
249                    "Color",
250                    Box::new(SavedBrickColor {
251                        r: 10,
252                        g: 20,
253                        b: 30,
254                        a: 255,
255                    }),
256                ),
257                ("bUseBrickColor", Box::new(false)),
258                ("bCastShadows", Box::new(true)),
259            ]),
260        ),
261    );
262
263    // 2: Spot light — narrow cone, non-default brightness/color.
264    world.bricks.push(
265        Brick {
266            position: (20, 0, 6).into(),
267            color: (255, 255, 0).into(),
268            ..Default::default()
269        }
270        .with_component(
271            assets::LiteralComponent::new("Component_SpotLight").with_data([
272                ("InnerConeAngle", Box::new(15.0f32) as Box<dyn AsBrdbValue>),
273                ("OuterConeAngle", Box::new(45.0f32)),
274                ("bEnabled", Box::new(true)),
275                ("Brightness", Box::new(300.0f32)),
276                ("Radius", Box::new(600.0f32)),
277                (
278                    "Color",
279                    Box::new(SavedBrickColor {
280                        r: 255,
281                        g: 0,
282                        b: 0,
283                        a: 255,
284                    }),
285                ),
286                ("bUseBrickColor", Box::new(false)),
287                ("bCastShadows", Box::new(true)),
288            ]),
289        ),
290    );
291
292    // 3: Interact — custom prompt text, hidden interaction.
293    world.bricks.push(
294        Brick {
295            position: (40, 0, 6).into(),
296            color: (0, 255, 255).into(),
297            ..Default::default()
298        }
299        .with_component(
300            assets::LiteralComponent::new("Component_Interact").with_data([
301                (
302                    "Message",
303                    Box::new("You interacted!".to_string()) as Box<dyn AsBrdbValue>,
304                ),
305                ("ConsoleTag", Box::new("fixture_interact".to_string())),
306                ("bAllowNearbyInteraction", Box::new(false)),
307                ("bHiddenInteraction", Box::new(true)),
308                ("PromptCustomLabel", Box::new("Open Door".to_string())),
309            ]),
310        ),
311    );
312
313    // 4: Buffer (ticks) — Input/Output are WireValue; non-default counters
314    // plus a Number/Bool value pair.
315    world.bricks.push(
316        Brick {
317            position: (60, 0, 1).into(),
318            color: (128, 0, 128).into(),
319            asset: assets::components::BufferTicks::default().brick(),
320            ..Default::default()
321        }
322        .with_component(assets::components::BufferTicks {
323            current_ticks: 3,
324            ticks_to_wait: 10,
325            input: WireValue::Number(2.5),
326            output: WireValue::Bool(true),
327            ..Default::default()
328        }),
329    );
330
331    // 5: Blend gate — Expr_MathBlend's InputA/InputB are each a WireValue
332    // (here an f64 and an i64, showing the value is polymorphic per-port);
333    // Blend itself is a plain f64.
334    world.bricks.push(
335        Brick {
336            position: (80, 0, 1).into(),
337            color: (0, 128, 0).into(),
338            asset: assets::components::LogicGate::Blend.brick(),
339            ..Default::default()
340        }
341        .with_component(
342            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
343                (
344                    "InputA".into(),
345                    Box::new(WireValue::Number(10.0)) as Box<dyn AsBrdbValue>,
346                ),
347                ("InputB".into(), Box::new(WireValue::Int(7))),
348                ("Blend".into(), Box::new(0.75f64)),
349            ])),
350        ),
351    );
352
353    world
354}
355
356fn entities_world() -> World {
357    // Mirror of examples/write_entity.rs's floating sub-grid — the first
358    // grid added after the always-present main grid 1 gets persistent index
359    // 2, so it lands at Grids/2 — plus a couple of main-grid (Grids/1)
360    // bricks. Both grids are single-chunk; note the *outer* Grids/1 vs
361    // Grids/2 folder order comes from a HashMap<usize, UnsavedGrid> in the
362    // writer and is NOT guaranteed stable run-to-run (see stability notes).
363    //
364    // register_all_components() is required here (matching
365    // test_write_entity_save, NOT the plain write_entity.rs example): without
366    // it, Entity_DynamicBrickGrid's class name is never registered and the
367    // write fails with `UnknownType("Entity_DynamicBrickGrid")` — confirmed
368    // by running the crate's own unmodified write_entity example.
369    let mut world = World::new();
370    world.register_all_components();
371    world.meta.bundle.description = "Entity fixture".to_string();
372
373    world.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (200, 50, 50).into(),
376        ..Default::default()
377    });
378    world.bricks.push(Brick {
379        position: (20, 0, 6).into(),
380        color: (50, 200, 50).into(),
381        ..Default::default()
382    });
383
384    world.add_brick_grid(
385        Entity {
386            frozen: true,
387            location: (0.0, 0.0, 40.0).into(),
388            ..Default::default()
389        },
390        [Brick {
391            position: (0, 0, 3).into(),
392            color: (0, 255, 0).into(),
393            ..Default::default()
394        }],
395    );
396
397    world
398}
399
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
476
477/// Current-build components in the Latest format: WireValue fields, dynamic
478/// arrays/maps (typed and empty) and a dynamic enum, plus a wire.
479fn components_latest_world() -> World {
480    let mut world = World::new();
481    world.meta.bundle.description = "Latest component fixture".to_string();
482    let gate = |x: i32, asset: &'static str| Brick {
483        position: (x, 0, 1).into(),
484        asset: BrickType::str(asset),
485        ..Default::default()
486    };
487
488    // 1: Blend gate with WireValue inputs (f64 and i64 alternatives).
489    let (blend, blend_id) = gate(0, "B_1x1_Gate_Expr_MathBlend")
490        .with_component(
491            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
492                (
493                    "InputA".into(),
494                    Box::new(WireValue::Number(1.5)) as Box<dyn AsBrdbValue>,
495                ),
496                ("InputB".into(), Box::new(WireValue::Int(-3))),
497                ("Blend".into(), Box::new(0.25f64)),
498            ])),
499        )
500        .with_id_split();
501    // 2: Buffer with Str / Bool alternatives.
502    let buffer =
503        gate(20, "B_1x1_Gate_BufferTicks").with_component(assets::components::BufferTicks {
504            ticks_to_wait: 4,
505            input: WireValue::Str("hello".into()),
506            output: WireValue::Bool(true),
507            buffered: WireValue::Vector {
508                x: 1.0,
509                y: -2.0,
510                z: 0.5,
511            },
512            ..Default::default()
513        });
514    // 3: Array variable holding i64 elements.
515    let array = gate(40, "B_1x1_Gate_Variable_Array").with_component(
516        assets::LiteralComponent::new("BrickComponentType_ArrayVar").with_data([(
517            "Value",
518            Box::new(BrdbDynamicArray::new(
519                "i64",
520                vec![BrdbValue::I64(7), BrdbValue::I64(300)],
521            )) as Box<dyn AsBrdbValue>,
522        )]),
523    );
524    // 4: Map variable from Str keys to f64 values.
525    let map = gate(60, "B_1x1_Gate_Variable_Map").with_component(
526        assets::LiteralComponent::new("BrickComponentType_MapVar").with_data([(
527            "Value",
528            Box::new(BrdbDynamicMap::new(
529                "Str",
530                "f64",
531                [(BrdbValue::String("k".into()), BrdbValue::F64(2.5))]
532                    .into_iter()
533                    .collect(),
534            )) as Box<dyn AsBrdbValue>,
535        )]),
536    );
537    // 5: Unset array variable: the default empty container.
538    let empty_array = gate(80, "B_1x1_Gate_Variable_Array")
539        .with_component(assets::LiteralComponent::new("BrickComponentType_ArrayVar"));
540    // 6: Integer to enum: a dynamic enum field.
541    let to_enum = gate(100, "B_1x1_Gate_Expr_IntegerToEnum").with_component(
542        assets::LiteralComponent::new("BrickComponentType_Expr_IntegerToEnum").with_data([
543            ("Input", Box::new(2i64) as Box<dyn AsBrdbValue>),
544            (
545                "TargetType",
546                Box::new(BrdbDynamicEnum::new("EBrickAxis", 0)),
547            ),
548        ]),
549    );
550    // 7: A rerouter fed by the blend gate.
551    let (reroute, reroute_id) = Brick {
552        position: (120, 0, 1).into(),
553        asset: assets::bricks::B_REROUTE,
554        ..Default::default()
555    }
556    .with_component(assets::components::Rerouter)
557    .with_id_split();
558
559    world.add_bricks([blend, buffer, array, map, empty_array, to_enum, reroute]);
560    world.add_wire_connection(
561        assets::components::LogicGate::Blend.output_of(blend_id),
562        assets::components::Rerouter::input_of(reroute_id),
563    );
564    // Embed only the structs these components use (what brs-js writes).
565    world.register_used_components();
566    world
567}
More examples
Hide additional examples
examples/write_brick.rs (line 8)
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}
examples/write_entity.rs (line 10)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_entity.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    world.meta.bundle.description = "Example World".to_string();
12    world.add_brick_grid(
13        Entity {
14            frozen: true,
15            location: (0.0, 0.0, 40.0).into(),
16            ..Default::default()
17        },
18        [Brick {
19            position: (0, 0, 3).into(),
20            color: (0, 255, 0).into(),
21            ..Default::default()
22        }],
23    );
24
25    db.save("example world", &world)?;
26
27    println!("{}", db.get_fs()?.render());
28
29    Ok(())
30}
examples/write_brz.rs (line 8)
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/write_prefab.rs (line 8)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_prefab.brz");
7
8    let mut world = World::new();
9    // A single 1x1 plate-ish brick (half-extent 5,5,2) at the origin so the
10    // bounds match the hand-captured reference prefab.
11    world.bricks.push(Brick {
12        asset: BrickType::Procedural {
13            asset: assets::bricks::PB_DEFAULT_BRICK.into(),
14            size: BrickSize { x: 5, y: 5, z: 2 },
15        },
16        position: (0, 0, 0).into(),
17        ..Default::default()
18    });
19
20    world.make_prefab();
21    println!(
22        "Prefab.json:\n{}",
23        serde_json::to_string_pretty(world.meta.prefab.as_ref().unwrap())?
24    );
25    println!(
26        "Bundle.json:\n{}",
27        serde_json::to_string_pretty(&world.meta.bundle)?
28    );
29
30    if path.exists() {
31        std::fs::remove_file(&path)?;
32    }
33    world.write_brz(&path)?;
34    println!("wrote {}", path.display());
35    Ok(())
36}
examples/write_wire.rs (line 10)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_wire.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    // Register the built-in component type/struct mappings so the gate and
12    // rerouter component types resolve when writing.
13    world.register_all_components();
14    world.meta.bundle.description = "Example World".to_string();
15
16    let (a, a_id) = Brick {
17        position: (0, 0, 1).into(),
18        color: (255, 0, 0).into(),
19        asset: assets::bricks::B_REROUTE,
20        ..Default::default()
21    }
22    .with_component(assets::components::Rerouter)
23    .with_id_split();
24    let (b, b_id) = Brick {
25        position: (15, 0, 1).into(),
26        color: (255, 0, 0).into(),
27        asset: assets::components::LogicGate::BoolNot.brick(),
28        ..Default::default()
29    }
30    .with_component(assets::components::LogicGate::BoolNot.component())
31    .with_id_split();
32
33    world.add_bricks([a, b]);
34    world.add_wire_connection(
35        assets::components::LogicGate::BoolNot.output_of(b_id),
36        assets::components::Rerouter::input_of(a_id),
37    );
38
39    db.save("example world", &world)?;
40
41    println!("{}", db.get_fs()?.render());
42
43    Ok(())
44}
Source

pub fn write_brdb(&self, path: impl AsRef<Path>) -> Result<(), BrError>

Examples found in repository?
examples/write_brick.rs (line 16)
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}
Source

pub fn write_brz(&self, path: impl AsRef<Path>) -> Result<(), BrError>

Examples found in repository?
examples/write_brz.rs (line 19)
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}
More examples
Hide additional examples
examples/write_prefab.rs (line 33)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_prefab.brz");
7
8    let mut world = World::new();
9    // A single 1x1 plate-ish brick (half-extent 5,5,2) at the origin so the
10    // bounds match the hand-captured reference prefab.
11    world.bricks.push(Brick {
12        asset: BrickType::Procedural {
13            asset: assets::bricks::PB_DEFAULT_BRICK.into(),
14            size: BrickSize { x: 5, y: 5, z: 2 },
15        },
16        position: (0, 0, 0).into(),
17        ..Default::default()
18    });
19
20    world.make_prefab();
21    println!(
22        "Prefab.json:\n{}",
23        serde_json::to_string_pretty(world.meta.prefab.as_ref().unwrap())?
24    );
25    println!(
26        "Bundle.json:\n{}",
27        serde_json::to_string_pretty(&world.meta.bundle)?
28    );
29
30    if path.exists() {
31        std::fs::remove_file(&path)?;
32    }
33    world.write_brz(&path)?;
34    println!("wrote {}", path.display());
35    Ok(())
36}
examples/write_prefab_spawner.rs (line 80)
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 to_brz_vec(&self) -> Result<Vec<u8>, BrError>

Examples found in repository?
examples/write_prefab_spawner.rs (line 20)
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 register_all_components(&mut self)

Load the full component schema and register all known type→struct mappings and wire port names from the built-in component database.

Examples found in repository?
examples/write_wire.rs (line 13)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_wire.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    // Register the built-in component type/struct mappings so the gate and
12    // rerouter component types resolve when writing.
13    world.register_all_components();
14    world.meta.bundle.description = "Example World".to_string();
15
16    let (a, a_id) = Brick {
17        position: (0, 0, 1).into(),
18        color: (255, 0, 0).into(),
19        asset: assets::bricks::B_REROUTE,
20        ..Default::default()
21    }
22    .with_component(assets::components::Rerouter)
23    .with_id_split();
24    let (b, b_id) = Brick {
25        position: (15, 0, 1).into(),
26        color: (255, 0, 0).into(),
27        asset: assets::components::LogicGate::BoolNot.brick(),
28        ..Default::default()
29    }
30    .with_component(assets::components::LogicGate::BoolNot.component())
31    .with_id_split();
32
33    world.add_bricks([a, b]);
34    world.add_wire_connection(
35        assets::components::LogicGate::BoolNot.output_of(b_id),
36        assets::components::Rerouter::input_of(a_id),
37    );
38
39    db.save("example world", &world)?;
40
41    println!("{}", db.get_fs()?.render());
42
43    Ok(())
44}
More examples
Hide additional examples
examples/write_fixtures.rs (line 180)
175fn wires_world() -> World {
176    // Mirror of examples/write_wire.rs (single grid, single chunk — fully
177    // deterministic), extended to 3 bricks/2 wires: a boolean NOT gate feeds
178    // one input of an AND gate, whose output feeds a rerouter.
179    let mut world = World::new();
180    world.register_all_components();
181    world.meta.bundle.description = "Wire fixture".to_string();
182
183    let (a, a_id) = Brick {
184        position: (30, 0, 1).into(),
185        color: (255, 0, 0).into(),
186        asset: assets::bricks::B_REROUTE,
187        ..Default::default()
188    }
189    .with_component(assets::components::Rerouter)
190    .with_id_split();
191    let (b, b_id) = Brick {
192        position: (15, 0, 1).into(),
193        color: (0, 255, 0).into(),
194        asset: assets::components::LogicGate::BoolAnd.brick(),
195        ..Default::default()
196    }
197    .with_component(assets::components::LogicGate::BoolAnd.component())
198    .with_id_split();
199    let (c, c_id) = Brick {
200        position: (0, 0, 1).into(),
201        color: (0, 0, 255).into(),
202        asset: assets::components::LogicGate::BoolNot.brick(),
203        ..Default::default()
204    }
205    .with_component(assets::components::LogicGate::BoolNot.component())
206    .with_id_split();
207
208    world.add_bricks([a, b, c]);
209    // Wire 1: NOT.output -> AND.inputA
210    world.add_wire_connection(
211        assets::components::LogicGate::BoolNot.output_of(c_id),
212        assets::components::LogicGate::BoolAnd.input_a_of(b_id),
213    );
214    // Wire 2: AND.output -> Rerouter.input
215    world.add_wire_connection(
216        assets::components::LogicGate::BoolAnd.output_of(b_id),
217        assets::components::Rerouter::input_of(a_id),
218    );
219
220    world
221}
222
223fn components_world() -> World {
224    // Single grid, single chunk (all positions < 2048) — fully deterministic.
225    // register_all_components() embeds the full component catalog so every
226    // type below (light/interact/buffer/expr) resolves; each
227    // component below carries non-default property values, and #4/#5 exercise
228    // a WireValue-typed property (BufferTicks' Input/Output, and the Blend
229    // gate's inputs).
230    let mut world = World::new();
231    world.register_all_components();
232    world.meta.bundle.description = "Component fixture".to_string();
233
234    // 1: Point light — non-default brightness/radius/color, decoupled from
235    // brick color (bUseBrickColor: false).
236    world.bricks.push(
237        Brick {
238            position: (0, 0, 6).into(),
239            color: (255, 255, 255).into(),
240            ..Default::default()
241        }
242        .with_component(
243            assets::LiteralComponent::new("Component_PointLight").with_data([
244                ("bMatchBrickShape", Box::new(false) as Box<dyn AsBrdbValue>),
245                ("bEnabled", Box::new(true)),
246                ("Brightness", Box::new(500.0f32)),
247                ("Radius", Box::new(800.0f32)),
248                (
249                    "Color",
250                    Box::new(SavedBrickColor {
251                        r: 10,
252                        g: 20,
253                        b: 30,
254                        a: 255,
255                    }),
256                ),
257                ("bUseBrickColor", Box::new(false)),
258                ("bCastShadows", Box::new(true)),
259            ]),
260        ),
261    );
262
263    // 2: Spot light — narrow cone, non-default brightness/color.
264    world.bricks.push(
265        Brick {
266            position: (20, 0, 6).into(),
267            color: (255, 255, 0).into(),
268            ..Default::default()
269        }
270        .with_component(
271            assets::LiteralComponent::new("Component_SpotLight").with_data([
272                ("InnerConeAngle", Box::new(15.0f32) as Box<dyn AsBrdbValue>),
273                ("OuterConeAngle", Box::new(45.0f32)),
274                ("bEnabled", Box::new(true)),
275                ("Brightness", Box::new(300.0f32)),
276                ("Radius", Box::new(600.0f32)),
277                (
278                    "Color",
279                    Box::new(SavedBrickColor {
280                        r: 255,
281                        g: 0,
282                        b: 0,
283                        a: 255,
284                    }),
285                ),
286                ("bUseBrickColor", Box::new(false)),
287                ("bCastShadows", Box::new(true)),
288            ]),
289        ),
290    );
291
292    // 3: Interact — custom prompt text, hidden interaction.
293    world.bricks.push(
294        Brick {
295            position: (40, 0, 6).into(),
296            color: (0, 255, 255).into(),
297            ..Default::default()
298        }
299        .with_component(
300            assets::LiteralComponent::new("Component_Interact").with_data([
301                (
302                    "Message",
303                    Box::new("You interacted!".to_string()) as Box<dyn AsBrdbValue>,
304                ),
305                ("ConsoleTag", Box::new("fixture_interact".to_string())),
306                ("bAllowNearbyInteraction", Box::new(false)),
307                ("bHiddenInteraction", Box::new(true)),
308                ("PromptCustomLabel", Box::new("Open Door".to_string())),
309            ]),
310        ),
311    );
312
313    // 4: Buffer (ticks) — Input/Output are WireValue; non-default counters
314    // plus a Number/Bool value pair.
315    world.bricks.push(
316        Brick {
317            position: (60, 0, 1).into(),
318            color: (128, 0, 128).into(),
319            asset: assets::components::BufferTicks::default().brick(),
320            ..Default::default()
321        }
322        .with_component(assets::components::BufferTicks {
323            current_ticks: 3,
324            ticks_to_wait: 10,
325            input: WireValue::Number(2.5),
326            output: WireValue::Bool(true),
327            ..Default::default()
328        }),
329    );
330
331    // 5: Blend gate — Expr_MathBlend's InputA/InputB are each a WireValue
332    // (here an f64 and an i64, showing the value is polymorphic per-port);
333    // Blend itself is a plain f64.
334    world.bricks.push(
335        Brick {
336            position: (80, 0, 1).into(),
337            color: (0, 128, 0).into(),
338            asset: assets::components::LogicGate::Blend.brick(),
339            ..Default::default()
340        }
341        .with_component(
342            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
343                (
344                    "InputA".into(),
345                    Box::new(WireValue::Number(10.0)) as Box<dyn AsBrdbValue>,
346                ),
347                ("InputB".into(), Box::new(WireValue::Int(7))),
348                ("Blend".into(), Box::new(0.75f64)),
349            ])),
350        ),
351    );
352
353    world
354}
355
356fn entities_world() -> World {
357    // Mirror of examples/write_entity.rs's floating sub-grid — the first
358    // grid added after the always-present main grid 1 gets persistent index
359    // 2, so it lands at Grids/2 — plus a couple of main-grid (Grids/1)
360    // bricks. Both grids are single-chunk; note the *outer* Grids/1 vs
361    // Grids/2 folder order comes from a HashMap<usize, UnsavedGrid> in the
362    // writer and is NOT guaranteed stable run-to-run (see stability notes).
363    //
364    // register_all_components() is required here (matching
365    // test_write_entity_save, NOT the plain write_entity.rs example): without
366    // it, Entity_DynamicBrickGrid's class name is never registered and the
367    // write fails with `UnknownType("Entity_DynamicBrickGrid")` — confirmed
368    // by running the crate's own unmodified write_entity example.
369    let mut world = World::new();
370    world.register_all_components();
371    world.meta.bundle.description = "Entity fixture".to_string();
372
373    world.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (200, 50, 50).into(),
376        ..Default::default()
377    });
378    world.bricks.push(Brick {
379        position: (20, 0, 6).into(),
380        color: (50, 200, 50).into(),
381        ..Default::default()
382    });
383
384    world.add_brick_grid(
385        Entity {
386            frozen: true,
387            location: (0.0, 0.0, 40.0).into(),
388            ..Default::default()
389        },
390        [Brick {
391            position: (0, 0, 3).into(),
392            color: (0, 255, 0).into(),
393            ..Default::default()
394        }],
395    );
396
397    world
398}
399
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
examples/write_prefab_spawner.rs (line 26)
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 register_used_components(&mut self)

Register only the components actually used by this world’s bricks, mirroring how the game embeds a bundle: ComponentsShared.schema and the global-data component tables carry only the data structs that appear, not the full catalog (which [register_all_components] embeds).

Call this AFTER all bricks/grids have been added. The component schema starts from the minimal SoA scaffolding and gains each used component’s data struct plus its transitive type dependencies; global-data component type/struct/port tables are rebuilt to match. Entity types are registered in full (the catalog is a single microchip-grid entry).

This keeps generated bundles byte-compatible with what the current game build writes — embedding the stale full catalog can make the game reject the schema (“while building schema: while reading struct count”).

Examples found in repository?
examples/write_fixtures.rs (line 565)
479fn components_latest_world() -> World {
480    let mut world = World::new();
481    world.meta.bundle.description = "Latest component fixture".to_string();
482    let gate = |x: i32, asset: &'static str| Brick {
483        position: (x, 0, 1).into(),
484        asset: BrickType::str(asset),
485        ..Default::default()
486    };
487
488    // 1: Blend gate with WireValue inputs (f64 and i64 alternatives).
489    let (blend, blend_id) = gate(0, "B_1x1_Gate_Expr_MathBlend")
490        .with_component(
491            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
492                (
493                    "InputA".into(),
494                    Box::new(WireValue::Number(1.5)) as Box<dyn AsBrdbValue>,
495                ),
496                ("InputB".into(), Box::new(WireValue::Int(-3))),
497                ("Blend".into(), Box::new(0.25f64)),
498            ])),
499        )
500        .with_id_split();
501    // 2: Buffer with Str / Bool alternatives.
502    let buffer =
503        gate(20, "B_1x1_Gate_BufferTicks").with_component(assets::components::BufferTicks {
504            ticks_to_wait: 4,
505            input: WireValue::Str("hello".into()),
506            output: WireValue::Bool(true),
507            buffered: WireValue::Vector {
508                x: 1.0,
509                y: -2.0,
510                z: 0.5,
511            },
512            ..Default::default()
513        });
514    // 3: Array variable holding i64 elements.
515    let array = gate(40, "B_1x1_Gate_Variable_Array").with_component(
516        assets::LiteralComponent::new("BrickComponentType_ArrayVar").with_data([(
517            "Value",
518            Box::new(BrdbDynamicArray::new(
519                "i64",
520                vec![BrdbValue::I64(7), BrdbValue::I64(300)],
521            )) as Box<dyn AsBrdbValue>,
522        )]),
523    );
524    // 4: Map variable from Str keys to f64 values.
525    let map = gate(60, "B_1x1_Gate_Variable_Map").with_component(
526        assets::LiteralComponent::new("BrickComponentType_MapVar").with_data([(
527            "Value",
528            Box::new(BrdbDynamicMap::new(
529                "Str",
530                "f64",
531                [(BrdbValue::String("k".into()), BrdbValue::F64(2.5))]
532                    .into_iter()
533                    .collect(),
534            )) as Box<dyn AsBrdbValue>,
535        )]),
536    );
537    // 5: Unset array variable: the default empty container.
538    let empty_array = gate(80, "B_1x1_Gate_Variable_Array")
539        .with_component(assets::LiteralComponent::new("BrickComponentType_ArrayVar"));
540    // 6: Integer to enum: a dynamic enum field.
541    let to_enum = gate(100, "B_1x1_Gate_Expr_IntegerToEnum").with_component(
542        assets::LiteralComponent::new("BrickComponentType_Expr_IntegerToEnum").with_data([
543            ("Input", Box::new(2i64) as Box<dyn AsBrdbValue>),
544            (
545                "TargetType",
546                Box::new(BrdbDynamicEnum::new("EBrickAxis", 0)),
547            ),
548        ]),
549    );
550    // 7: A rerouter fed by the blend gate.
551    let (reroute, reroute_id) = Brick {
552        position: (120, 0, 1).into(),
553        asset: assets::bricks::B_REROUTE,
554        ..Default::default()
555    }
556    .with_component(assets::components::Rerouter)
557    .with_id_split();
558
559    world.add_bricks([blend, buffer, array, map, empty_array, to_enum, reroute]);
560    world.add_wire_connection(
561        assets::components::LogicGate::Blend.output_of(blend_id),
562        assets::components::Rerouter::input_of(reroute_id),
563    );
564    // Embed only the structs these components use (what brs-js writes).
565    world.register_used_components();
566    world
567}
Source

pub fn register_component_schema(&mut self, schema_str: &str)

Parse a schema string and merge its definitions.

Source

pub fn register_component(&mut self, struct_name: &str)

Pull a single struct from the max schema.

Source

pub fn brick_bounds(&self) -> Option<(Position, Position)>

Inclusive axis-aligned bounding box over the main-grid bricks, in brick units, as (min, max). Returns None if there are no main-grid bricks. Non-main grids (microchips) are excluded — their bricks live inside an entity and are offset to the chunk center.

Source

pub fn make_prefab(&mut self)

Mark this world’s metadata as a prefab: sets the bundle type to "Prefab" and fills Meta/Prefab.json with pivots/bounds computed from the main-grid brick bounding box (see World::brick_bounds). The write path then emits a prefab bundle (Bundle.json + Prefab.json, plus the optional Screenshot/Thumbnail; no World.json).

Examples found in repository?
examples/write_prefab.rs (line 20)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_prefab.brz");
7
8    let mut world = World::new();
9    // A single 1x1 plate-ish brick (half-extent 5,5,2) at the origin so the
10    // bounds match the hand-captured reference prefab.
11    world.bricks.push(Brick {
12        asset: BrickType::Procedural {
13            asset: assets::bricks::PB_DEFAULT_BRICK.into(),
14            size: BrickSize { x: 5, y: 5, z: 2 },
15        },
16        position: (0, 0, 0).into(),
17        ..Default::default()
18    });
19
20    world.make_prefab();
21    println!(
22        "Prefab.json:\n{}",
23        serde_json::to_string_pretty(world.meta.prefab.as_ref().unwrap())?
24    );
25    println!(
26        "Bundle.json:\n{}",
27        serde_json::to_string_pretty(&world.meta.bundle)?
28    );
29
30    if path.exists() {
31        std::fs::remove_file(&path)?;
32    }
33    world.write_brz(&path)?;
34    println!("wrote {}", path.display());
35    Ok(())
36}
More examples
Hide additional examples
examples/write_fixtures.rs (line 413)
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
examples/write_prefab_spawner.rs (line 19)
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 add_prefab(&mut self, brz_bytes: impl Into<Vec<u8>>) -> String

Embed a prefab archive, content-addressed the way the game does: Prefabs/Uploads/<BLAKE3-uppercase-hex>.brz. Returns that path — the exact string to store in a Prefab component property (bundle_path_ref), e.g. on BrickComponentType_PrefabSpawn or BrickComponentType_WireGraph_Exec_PrefabSpawner.

Examples found in repository?
examples/write_fixtures.rs (line 428)
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
More examples
Hide additional examples
examples/write_prefab_spawner.rs (line 30)
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 add_prefab_world(&mut self, world: &World) -> Result<String, BrError>

Serialize world to an in-memory .brz and embed it as a prefab.

Source

pub fn to_unsaved(&self) -> Result<UnsavedFs, BrError>

Examples found in repository?
examples/write_fixtures.rs (line 415)
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
476
477/// Current-build components in the Latest format: WireValue fields, dynamic
478/// arrays/maps (typed and empty) and a dynamic enum, plus a wire.
479fn components_latest_world() -> World {
480    let mut world = World::new();
481    world.meta.bundle.description = "Latest component fixture".to_string();
482    let gate = |x: i32, asset: &'static str| Brick {
483        position: (x, 0, 1).into(),
484        asset: BrickType::str(asset),
485        ..Default::default()
486    };
487
488    // 1: Blend gate with WireValue inputs (f64 and i64 alternatives).
489    let (blend, blend_id) = gate(0, "B_1x1_Gate_Expr_MathBlend")
490        .with_component(
491            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
492                (
493                    "InputA".into(),
494                    Box::new(WireValue::Number(1.5)) as Box<dyn AsBrdbValue>,
495                ),
496                ("InputB".into(), Box::new(WireValue::Int(-3))),
497                ("Blend".into(), Box::new(0.25f64)),
498            ])),
499        )
500        .with_id_split();
501    // 2: Buffer with Str / Bool alternatives.
502    let buffer =
503        gate(20, "B_1x1_Gate_BufferTicks").with_component(assets::components::BufferTicks {
504            ticks_to_wait: 4,
505            input: WireValue::Str("hello".into()),
506            output: WireValue::Bool(true),
507            buffered: WireValue::Vector {
508                x: 1.0,
509                y: -2.0,
510                z: 0.5,
511            },
512            ..Default::default()
513        });
514    // 3: Array variable holding i64 elements.
515    let array = gate(40, "B_1x1_Gate_Variable_Array").with_component(
516        assets::LiteralComponent::new("BrickComponentType_ArrayVar").with_data([(
517            "Value",
518            Box::new(BrdbDynamicArray::new(
519                "i64",
520                vec![BrdbValue::I64(7), BrdbValue::I64(300)],
521            )) as Box<dyn AsBrdbValue>,
522        )]),
523    );
524    // 4: Map variable from Str keys to f64 values.
525    let map = gate(60, "B_1x1_Gate_Variable_Map").with_component(
526        assets::LiteralComponent::new("BrickComponentType_MapVar").with_data([(
527            "Value",
528            Box::new(BrdbDynamicMap::new(
529                "Str",
530                "f64",
531                [(BrdbValue::String("k".into()), BrdbValue::F64(2.5))]
532                    .into_iter()
533                    .collect(),
534            )) as Box<dyn AsBrdbValue>,
535        )]),
536    );
537    // 5: Unset array variable: the default empty container.
538    let empty_array = gate(80, "B_1x1_Gate_Variable_Array")
539        .with_component(assets::LiteralComponent::new("BrickComponentType_ArrayVar"));
540    // 6: Integer to enum: a dynamic enum field.
541    let to_enum = gate(100, "B_1x1_Gate_Expr_IntegerToEnum").with_component(
542        assets::LiteralComponent::new("BrickComponentType_Expr_IntegerToEnum").with_data([
543            ("Input", Box::new(2i64) as Box<dyn AsBrdbValue>),
544            (
545                "TargetType",
546                Box::new(BrdbDynamicEnum::new("EBrickAxis", 0)),
547            ),
548        ]),
549    );
550    // 7: A rerouter fed by the blend gate.
551    let (reroute, reroute_id) = Brick {
552        position: (120, 0, 1).into(),
553        asset: assets::bricks::B_REROUTE,
554        ..Default::default()
555    }
556    .with_component(assets::components::Rerouter)
557    .with_id_split();
558
559    world.add_bricks([blend, buffer, array, map, empty_array, to_enum, reroute]);
560    world.add_wire_connection(
561        assets::components::LogicGate::Blend.output_of(blend_id),
562        assets::components::Rerouter::input_of(reroute_id),
563    );
564    // Embed only the structs these components use (what brs-js writes).
565    world.register_used_components();
566    world
567}
568
569fn hash_archive(
570    path: &PathBuf,
571) -> Result<BTreeMap<String, serde_json::Value>, Box<dyn std::error::Error>> {
572    fn collect(fs: &BrFs, prefix: &str, out: &mut Vec<(String, Option<i64>)>) {
573        match fs {
574            BrFs::Root(children) => {
575                for (n, c) in children {
576                    collect(c, n, out);
577                }
578            }
579            BrFs::Folder(_, children) => {
580                for (n, c) in children {
581                    collect(c, &format!("{prefix}/{n}"), out);
582                }
583            }
584            BrFs::File(f) => out.push((prefix.to_string(), f.content_id)),
585        }
586    }
587    let reader = Brz::open(path)?.into_reader();
588    let reader = &*reader;
589    let mut files = Vec::new();
590    collect(&reader.get_fs()?, "", &mut files);
591    let mut out = BTreeMap::new();
592    for (p, content_id) in files {
593        let content = match content_id {
594            Some(id) => reader.find_blob(id)?.read()?,
595            None => Vec::new(),
596        };
597        out.insert(
598            p,
599            serde_json::json!({
600                "blake3": blake3::hash(&content).to_hex().to_string(),
601                "len": content.len(),
602            }),
603        );
604    }
605    Ok(out)
606}
607
608fn main() -> Result<(), Box<dyn std::error::Error>> {
609    let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("fixtures");
610    fs::create_dir_all(dir.join("schemas"))?;
611
612    let mut hashes = BTreeMap::new();
613    for (name, world) in [
614        ("brick", brick_world()),
615        ("features", features_world()),
616        ("chunks", chunks_world()),
617        ("wires", wires_world()),
618        ("components", components_world()),
619        ("entities", entities_world()),
620        ("spawner", spawner_world()),
621        ("features_latest", features_latest_world()),
622        ("components_latest", components_latest_world()),
623        ("entities_latest", entities_latest_world()),
624    ] {
625        let pending = world.to_unsaved()?.to_pending()?;
626        // raw variant: no zstd anywhere — byte-comparable across languages
627        let raw_path = dir.join(format!("{name}_raw.brz"));
628        let mut f = fs::File::create(&raw_path)?;
629        pending.clone().to_brz_data(None)?.write(&mut f, None)?;
630        // compressed variant: zstd level 14 (matches Brz::save)
631        let mut f = fs::File::create(dir.join(format!("{name}.brz")))?;
632        pending.to_brz_data(Some(14))?.write(&mut f, Some(14))?;
633
634        // .brdb variant: content parity only (the .brdb container is not
635        // byte-deterministic across runs).
636        let db_path = dir.join(format!("{name}.brdb"));
637        let _ = fs::remove_file(&db_path);
638        Brdb::create(&db_path)?.save("Fixture", &world)?;
639
640        hashes.insert(name.to_string(), hash_archive(&raw_path)?);
641    }
642    fs::write(
643        dir.join("hashes.json"),
644        serde_json::to_string_pretty(&hashes)?,
645    )?;
646
647    // The nine embedded schemas as binary msgpack (the exact bytes the
648    // writer embeds as *.schema files inside archives).
649    for (name, schema) in [
650        ("BRSavedGlobalDataSoA", schemas::global_data_schema()),
651        ("BRSavedOwnerTableSoA", schemas::owners_schema()),
652        (
653            "BRSavedBrickChunkIndexSoA",
654            schemas::bricks_chunk_index_schema(),
655        ),
656        ("BRSavedBrickChunkSoA", schemas::bricks_chunks_schema()),
657        ("BRSavedWireChunkSoA", schemas::bricks_wires_schema()),
658        (
659            "BRSavedComponentChunkSoA",
660            schemas::bricks_components_schema_min(),
661        ),
662        (
663            "BRSavedComponentChunkSoA_max",
664            schemas::bricks_components_schema_max(),
665        ),
666        (
667            "BRSavedEntityChunkIndexSoA",
668            schemas::entities_chunk_index_schema(),
669        ),
670        ("BRSavedEntityChunkSoA", schemas::entities_chunks_schema()),
671    ] {
672        // Each schema in its own format (the current max schema has a
673        // types table, so it is written in the Latest form).
674        fs::write(dir.join(format!("schemas/{name}.bin")), schema.to_bytes()?)?;
675    }
676    eprintln!("fixtures written to {}", dir.display());
677    Ok(())
678}
Source

pub fn add_brick(&mut self, brick: Brick)

Add a single brick to the world

Source

pub fn add_bricks(&mut self, bricks: impl IntoIterator<Item = Brick>)

Add multiple bricks to the world

Examples found in repository?
examples/write_wire.rs (line 33)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_wire.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    // Register the built-in component type/struct mappings so the gate and
12    // rerouter component types resolve when writing.
13    world.register_all_components();
14    world.meta.bundle.description = "Example World".to_string();
15
16    let (a, a_id) = Brick {
17        position: (0, 0, 1).into(),
18        color: (255, 0, 0).into(),
19        asset: assets::bricks::B_REROUTE,
20        ..Default::default()
21    }
22    .with_component(assets::components::Rerouter)
23    .with_id_split();
24    let (b, b_id) = Brick {
25        position: (15, 0, 1).into(),
26        color: (255, 0, 0).into(),
27        asset: assets::components::LogicGate::BoolNot.brick(),
28        ..Default::default()
29    }
30    .with_component(assets::components::LogicGate::BoolNot.component())
31    .with_id_split();
32
33    world.add_bricks([a, b]);
34    world.add_wire_connection(
35        assets::components::LogicGate::BoolNot.output_of(b_id),
36        assets::components::Rerouter::input_of(a_id),
37    );
38
39    db.save("example world", &world)?;
40
41    println!("{}", db.get_fs()?.render());
42
43    Ok(())
44}
More examples
Hide additional examples
examples/write_fixtures.rs (line 208)
175fn wires_world() -> World {
176    // Mirror of examples/write_wire.rs (single grid, single chunk — fully
177    // deterministic), extended to 3 bricks/2 wires: a boolean NOT gate feeds
178    // one input of an AND gate, whose output feeds a rerouter.
179    let mut world = World::new();
180    world.register_all_components();
181    world.meta.bundle.description = "Wire fixture".to_string();
182
183    let (a, a_id) = Brick {
184        position: (30, 0, 1).into(),
185        color: (255, 0, 0).into(),
186        asset: assets::bricks::B_REROUTE,
187        ..Default::default()
188    }
189    .with_component(assets::components::Rerouter)
190    .with_id_split();
191    let (b, b_id) = Brick {
192        position: (15, 0, 1).into(),
193        color: (0, 255, 0).into(),
194        asset: assets::components::LogicGate::BoolAnd.brick(),
195        ..Default::default()
196    }
197    .with_component(assets::components::LogicGate::BoolAnd.component())
198    .with_id_split();
199    let (c, c_id) = Brick {
200        position: (0, 0, 1).into(),
201        color: (0, 0, 255).into(),
202        asset: assets::components::LogicGate::BoolNot.brick(),
203        ..Default::default()
204    }
205    .with_component(assets::components::LogicGate::BoolNot.component())
206    .with_id_split();
207
208    world.add_bricks([a, b, c]);
209    // Wire 1: NOT.output -> AND.inputA
210    world.add_wire_connection(
211        assets::components::LogicGate::BoolNot.output_of(c_id),
212        assets::components::LogicGate::BoolAnd.input_a_of(b_id),
213    );
214    // Wire 2: AND.output -> Rerouter.input
215    world.add_wire_connection(
216        assets::components::LogicGate::BoolAnd.output_of(b_id),
217        assets::components::Rerouter::input_of(a_id),
218    );
219
220    world
221}
222
223fn components_world() -> World {
224    // Single grid, single chunk (all positions < 2048) — fully deterministic.
225    // register_all_components() embeds the full component catalog so every
226    // type below (light/interact/buffer/expr) resolves; each
227    // component below carries non-default property values, and #4/#5 exercise
228    // a WireValue-typed property (BufferTicks' Input/Output, and the Blend
229    // gate's inputs).
230    let mut world = World::new();
231    world.register_all_components();
232    world.meta.bundle.description = "Component fixture".to_string();
233
234    // 1: Point light — non-default brightness/radius/color, decoupled from
235    // brick color (bUseBrickColor: false).
236    world.bricks.push(
237        Brick {
238            position: (0, 0, 6).into(),
239            color: (255, 255, 255).into(),
240            ..Default::default()
241        }
242        .with_component(
243            assets::LiteralComponent::new("Component_PointLight").with_data([
244                ("bMatchBrickShape", Box::new(false) as Box<dyn AsBrdbValue>),
245                ("bEnabled", Box::new(true)),
246                ("Brightness", Box::new(500.0f32)),
247                ("Radius", Box::new(800.0f32)),
248                (
249                    "Color",
250                    Box::new(SavedBrickColor {
251                        r: 10,
252                        g: 20,
253                        b: 30,
254                        a: 255,
255                    }),
256                ),
257                ("bUseBrickColor", Box::new(false)),
258                ("bCastShadows", Box::new(true)),
259            ]),
260        ),
261    );
262
263    // 2: Spot light — narrow cone, non-default brightness/color.
264    world.bricks.push(
265        Brick {
266            position: (20, 0, 6).into(),
267            color: (255, 255, 0).into(),
268            ..Default::default()
269        }
270        .with_component(
271            assets::LiteralComponent::new("Component_SpotLight").with_data([
272                ("InnerConeAngle", Box::new(15.0f32) as Box<dyn AsBrdbValue>),
273                ("OuterConeAngle", Box::new(45.0f32)),
274                ("bEnabled", Box::new(true)),
275                ("Brightness", Box::new(300.0f32)),
276                ("Radius", Box::new(600.0f32)),
277                (
278                    "Color",
279                    Box::new(SavedBrickColor {
280                        r: 255,
281                        g: 0,
282                        b: 0,
283                        a: 255,
284                    }),
285                ),
286                ("bUseBrickColor", Box::new(false)),
287                ("bCastShadows", Box::new(true)),
288            ]),
289        ),
290    );
291
292    // 3: Interact — custom prompt text, hidden interaction.
293    world.bricks.push(
294        Brick {
295            position: (40, 0, 6).into(),
296            color: (0, 255, 255).into(),
297            ..Default::default()
298        }
299        .with_component(
300            assets::LiteralComponent::new("Component_Interact").with_data([
301                (
302                    "Message",
303                    Box::new("You interacted!".to_string()) as Box<dyn AsBrdbValue>,
304                ),
305                ("ConsoleTag", Box::new("fixture_interact".to_string())),
306                ("bAllowNearbyInteraction", Box::new(false)),
307                ("bHiddenInteraction", Box::new(true)),
308                ("PromptCustomLabel", Box::new("Open Door".to_string())),
309            ]),
310        ),
311    );
312
313    // 4: Buffer (ticks) — Input/Output are WireValue; non-default counters
314    // plus a Number/Bool value pair.
315    world.bricks.push(
316        Brick {
317            position: (60, 0, 1).into(),
318            color: (128, 0, 128).into(),
319            asset: assets::components::BufferTicks::default().brick(),
320            ..Default::default()
321        }
322        .with_component(assets::components::BufferTicks {
323            current_ticks: 3,
324            ticks_to_wait: 10,
325            input: WireValue::Number(2.5),
326            output: WireValue::Bool(true),
327            ..Default::default()
328        }),
329    );
330
331    // 5: Blend gate — Expr_MathBlend's InputA/InputB are each a WireValue
332    // (here an f64 and an i64, showing the value is polymorphic per-port);
333    // Blend itself is a plain f64.
334    world.bricks.push(
335        Brick {
336            position: (80, 0, 1).into(),
337            color: (0, 128, 0).into(),
338            asset: assets::components::LogicGate::Blend.brick(),
339            ..Default::default()
340        }
341        .with_component(
342            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
343                (
344                    "InputA".into(),
345                    Box::new(WireValue::Number(10.0)) as Box<dyn AsBrdbValue>,
346                ),
347                ("InputB".into(), Box::new(WireValue::Int(7))),
348                ("Blend".into(), Box::new(0.75f64)),
349            ])),
350        ),
351    );
352
353    world
354}
355
356fn entities_world() -> World {
357    // Mirror of examples/write_entity.rs's floating sub-grid — the first
358    // grid added after the always-present main grid 1 gets persistent index
359    // 2, so it lands at Grids/2 — plus a couple of main-grid (Grids/1)
360    // bricks. Both grids are single-chunk; note the *outer* Grids/1 vs
361    // Grids/2 folder order comes from a HashMap<usize, UnsavedGrid> in the
362    // writer and is NOT guaranteed stable run-to-run (see stability notes).
363    //
364    // register_all_components() is required here (matching
365    // test_write_entity_save, NOT the plain write_entity.rs example): without
366    // it, Entity_DynamicBrickGrid's class name is never registered and the
367    // write fails with `UnknownType("Entity_DynamicBrickGrid")` — confirmed
368    // by running the crate's own unmodified write_entity example.
369    let mut world = World::new();
370    world.register_all_components();
371    world.meta.bundle.description = "Entity fixture".to_string();
372
373    world.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (200, 50, 50).into(),
376        ..Default::default()
377    });
378    world.bricks.push(Brick {
379        position: (20, 0, 6).into(),
380        color: (50, 200, 50).into(),
381        ..Default::default()
382    });
383
384    world.add_brick_grid(
385        Entity {
386            frozen: true,
387            location: (0.0, 0.0, 40.0).into(),
388            ..Default::default()
389        },
390        [Brick {
391            position: (0, 0, 3).into(),
392            color: (0, 255, 0).into(),
393            ..Default::default()
394        }],
395    );
396
397    world
398}
399
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
476
477/// Current-build components in the Latest format: WireValue fields, dynamic
478/// arrays/maps (typed and empty) and a dynamic enum, plus a wire.
479fn components_latest_world() -> World {
480    let mut world = World::new();
481    world.meta.bundle.description = "Latest component fixture".to_string();
482    let gate = |x: i32, asset: &'static str| Brick {
483        position: (x, 0, 1).into(),
484        asset: BrickType::str(asset),
485        ..Default::default()
486    };
487
488    // 1: Blend gate with WireValue inputs (f64 and i64 alternatives).
489    let (blend, blend_id) = gate(0, "B_1x1_Gate_Expr_MathBlend")
490        .with_component(
491            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
492                (
493                    "InputA".into(),
494                    Box::new(WireValue::Number(1.5)) as Box<dyn AsBrdbValue>,
495                ),
496                ("InputB".into(), Box::new(WireValue::Int(-3))),
497                ("Blend".into(), Box::new(0.25f64)),
498            ])),
499        )
500        .with_id_split();
501    // 2: Buffer with Str / Bool alternatives.
502    let buffer =
503        gate(20, "B_1x1_Gate_BufferTicks").with_component(assets::components::BufferTicks {
504            ticks_to_wait: 4,
505            input: WireValue::Str("hello".into()),
506            output: WireValue::Bool(true),
507            buffered: WireValue::Vector {
508                x: 1.0,
509                y: -2.0,
510                z: 0.5,
511            },
512            ..Default::default()
513        });
514    // 3: Array variable holding i64 elements.
515    let array = gate(40, "B_1x1_Gate_Variable_Array").with_component(
516        assets::LiteralComponent::new("BrickComponentType_ArrayVar").with_data([(
517            "Value",
518            Box::new(BrdbDynamicArray::new(
519                "i64",
520                vec![BrdbValue::I64(7), BrdbValue::I64(300)],
521            )) as Box<dyn AsBrdbValue>,
522        )]),
523    );
524    // 4: Map variable from Str keys to f64 values.
525    let map = gate(60, "B_1x1_Gate_Variable_Map").with_component(
526        assets::LiteralComponent::new("BrickComponentType_MapVar").with_data([(
527            "Value",
528            Box::new(BrdbDynamicMap::new(
529                "Str",
530                "f64",
531                [(BrdbValue::String("k".into()), BrdbValue::F64(2.5))]
532                    .into_iter()
533                    .collect(),
534            )) as Box<dyn AsBrdbValue>,
535        )]),
536    );
537    // 5: Unset array variable: the default empty container.
538    let empty_array = gate(80, "B_1x1_Gate_Variable_Array")
539        .with_component(assets::LiteralComponent::new("BrickComponentType_ArrayVar"));
540    // 6: Integer to enum: a dynamic enum field.
541    let to_enum = gate(100, "B_1x1_Gate_Expr_IntegerToEnum").with_component(
542        assets::LiteralComponent::new("BrickComponentType_Expr_IntegerToEnum").with_data([
543            ("Input", Box::new(2i64) as Box<dyn AsBrdbValue>),
544            (
545                "TargetType",
546                Box::new(BrdbDynamicEnum::new("EBrickAxis", 0)),
547            ),
548        ]),
549    );
550    // 7: A rerouter fed by the blend gate.
551    let (reroute, reroute_id) = Brick {
552        position: (120, 0, 1).into(),
553        asset: assets::bricks::B_REROUTE,
554        ..Default::default()
555    }
556    .with_component(assets::components::Rerouter)
557    .with_id_split();
558
559    world.add_bricks([blend, buffer, array, map, empty_array, to_enum, reroute]);
560    world.add_wire_connection(
561        assets::components::LogicGate::Blend.output_of(blend_id),
562        assets::components::Rerouter::input_of(reroute_id),
563    );
564    // Embed only the structs these components use (what brs-js writes).
565    world.register_used_components();
566    world
567}
examples/write_prefab_spawner.rs (line 65)
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 add_entity(&mut self, entity: Entity)

Source

pub fn add_brick_grid( &mut self, entity: Entity, bricks: impl IntoIterator<Item = Brick>, )

Examples found in repository?
examples/write_entity.rs (lines 12-23)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_entity.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    world.meta.bundle.description = "Example World".to_string();
12    world.add_brick_grid(
13        Entity {
14            frozen: true,
15            location: (0.0, 0.0, 40.0).into(),
16            ..Default::default()
17        },
18        [Brick {
19            position: (0, 0, 3).into(),
20            color: (0, 255, 0).into(),
21            ..Default::default()
22        }],
23    );
24
25    db.save("example world", &world)?;
26
27    println!("{}", db.get_fs()?.render());
28
29    Ok(())
30}
More examples
Hide additional examples
examples/write_fixtures.rs (lines 384-395)
356fn entities_world() -> World {
357    // Mirror of examples/write_entity.rs's floating sub-grid — the first
358    // grid added after the always-present main grid 1 gets persistent index
359    // 2, so it lands at Grids/2 — plus a couple of main-grid (Grids/1)
360    // bricks. Both grids are single-chunk; note the *outer* Grids/1 vs
361    // Grids/2 folder order comes from a HashMap<usize, UnsavedGrid> in the
362    // writer and is NOT guaranteed stable run-to-run (see stability notes).
363    //
364    // register_all_components() is required here (matching
365    // test_write_entity_save, NOT the plain write_entity.rs example): without
366    // it, Entity_DynamicBrickGrid's class name is never registered and the
367    // write fails with `UnknownType("Entity_DynamicBrickGrid")` — confirmed
368    // by running the crate's own unmodified write_entity example.
369    let mut world = World::new();
370    world.register_all_components();
371    world.meta.bundle.description = "Entity fixture".to_string();
372
373    world.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (200, 50, 50).into(),
376        ..Default::default()
377    });
378    world.bricks.push(Brick {
379        position: (20, 0, 6).into(),
380        color: (50, 200, 50).into(),
381        ..Default::default()
382    });
383
384    world.add_brick_grid(
385        Entity {
386            frozen: true,
387            location: (0.0, 0.0, 40.0).into(),
388            ..Default::default()
389        },
390        [Brick {
391            position: (0, 0, 3).into(),
392            color: (0, 255, 0).into(),
393            ..Default::default()
394        }],
395    );
396
397    world
398}
399
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
Source

pub fn add_wire(&mut self, conn: WireConnection)

Add a single wire connection to the world

Source

pub fn add_wires(&mut self, wires: impl IntoIterator<Item = WireConnection>)

Add multiple wire connections to the world

Source

pub fn add_wire_connection(&mut self, source: WirePort, target: WirePort)

Add a wire connection from one port to another

Examples found in repository?
examples/write_wire.rs (lines 34-37)
5fn main() -> Result<(), Box<dyn std::error::Error>> {
6    let path = PathBuf::from("./example_wire.brdb");
7
8    // Ensures the memory db can be created without errors
9    let db = Brdb::new(&path)?.into_reader();
10    let mut world = World::new();
11    // Register the built-in component type/struct mappings so the gate and
12    // rerouter component types resolve when writing.
13    world.register_all_components();
14    world.meta.bundle.description = "Example World".to_string();
15
16    let (a, a_id) = Brick {
17        position: (0, 0, 1).into(),
18        color: (255, 0, 0).into(),
19        asset: assets::bricks::B_REROUTE,
20        ..Default::default()
21    }
22    .with_component(assets::components::Rerouter)
23    .with_id_split();
24    let (b, b_id) = Brick {
25        position: (15, 0, 1).into(),
26        color: (255, 0, 0).into(),
27        asset: assets::components::LogicGate::BoolNot.brick(),
28        ..Default::default()
29    }
30    .with_component(assets::components::LogicGate::BoolNot.component())
31    .with_id_split();
32
33    world.add_bricks([a, b]);
34    world.add_wire_connection(
35        assets::components::LogicGate::BoolNot.output_of(b_id),
36        assets::components::Rerouter::input_of(a_id),
37    );
38
39    db.save("example world", &world)?;
40
41    println!("{}", db.get_fs()?.render());
42
43    Ok(())
44}
More examples
Hide additional examples
examples/write_fixtures.rs (lines 210-213)
175fn wires_world() -> World {
176    // Mirror of examples/write_wire.rs (single grid, single chunk — fully
177    // deterministic), extended to 3 bricks/2 wires: a boolean NOT gate feeds
178    // one input of an AND gate, whose output feeds a rerouter.
179    let mut world = World::new();
180    world.register_all_components();
181    world.meta.bundle.description = "Wire fixture".to_string();
182
183    let (a, a_id) = Brick {
184        position: (30, 0, 1).into(),
185        color: (255, 0, 0).into(),
186        asset: assets::bricks::B_REROUTE,
187        ..Default::default()
188    }
189    .with_component(assets::components::Rerouter)
190    .with_id_split();
191    let (b, b_id) = Brick {
192        position: (15, 0, 1).into(),
193        color: (0, 255, 0).into(),
194        asset: assets::components::LogicGate::BoolAnd.brick(),
195        ..Default::default()
196    }
197    .with_component(assets::components::LogicGate::BoolAnd.component())
198    .with_id_split();
199    let (c, c_id) = Brick {
200        position: (0, 0, 1).into(),
201        color: (0, 0, 255).into(),
202        asset: assets::components::LogicGate::BoolNot.brick(),
203        ..Default::default()
204    }
205    .with_component(assets::components::LogicGate::BoolNot.component())
206    .with_id_split();
207
208    world.add_bricks([a, b, c]);
209    // Wire 1: NOT.output -> AND.inputA
210    world.add_wire_connection(
211        assets::components::LogicGate::BoolNot.output_of(c_id),
212        assets::components::LogicGate::BoolAnd.input_a_of(b_id),
213    );
214    // Wire 2: AND.output -> Rerouter.input
215    world.add_wire_connection(
216        assets::components::LogicGate::BoolAnd.output_of(b_id),
217        assets::components::Rerouter::input_of(a_id),
218    );
219
220    world
221}
222
223fn components_world() -> World {
224    // Single grid, single chunk (all positions < 2048) — fully deterministic.
225    // register_all_components() embeds the full component catalog so every
226    // type below (light/interact/buffer/expr) resolves; each
227    // component below carries non-default property values, and #4/#5 exercise
228    // a WireValue-typed property (BufferTicks' Input/Output, and the Blend
229    // gate's inputs).
230    let mut world = World::new();
231    world.register_all_components();
232    world.meta.bundle.description = "Component fixture".to_string();
233
234    // 1: Point light — non-default brightness/radius/color, decoupled from
235    // brick color (bUseBrickColor: false).
236    world.bricks.push(
237        Brick {
238            position: (0, 0, 6).into(),
239            color: (255, 255, 255).into(),
240            ..Default::default()
241        }
242        .with_component(
243            assets::LiteralComponent::new("Component_PointLight").with_data([
244                ("bMatchBrickShape", Box::new(false) as Box<dyn AsBrdbValue>),
245                ("bEnabled", Box::new(true)),
246                ("Brightness", Box::new(500.0f32)),
247                ("Radius", Box::new(800.0f32)),
248                (
249                    "Color",
250                    Box::new(SavedBrickColor {
251                        r: 10,
252                        g: 20,
253                        b: 30,
254                        a: 255,
255                    }),
256                ),
257                ("bUseBrickColor", Box::new(false)),
258                ("bCastShadows", Box::new(true)),
259            ]),
260        ),
261    );
262
263    // 2: Spot light — narrow cone, non-default brightness/color.
264    world.bricks.push(
265        Brick {
266            position: (20, 0, 6).into(),
267            color: (255, 255, 0).into(),
268            ..Default::default()
269        }
270        .with_component(
271            assets::LiteralComponent::new("Component_SpotLight").with_data([
272                ("InnerConeAngle", Box::new(15.0f32) as Box<dyn AsBrdbValue>),
273                ("OuterConeAngle", Box::new(45.0f32)),
274                ("bEnabled", Box::new(true)),
275                ("Brightness", Box::new(300.0f32)),
276                ("Radius", Box::new(600.0f32)),
277                (
278                    "Color",
279                    Box::new(SavedBrickColor {
280                        r: 255,
281                        g: 0,
282                        b: 0,
283                        a: 255,
284                    }),
285                ),
286                ("bUseBrickColor", Box::new(false)),
287                ("bCastShadows", Box::new(true)),
288            ]),
289        ),
290    );
291
292    // 3: Interact — custom prompt text, hidden interaction.
293    world.bricks.push(
294        Brick {
295            position: (40, 0, 6).into(),
296            color: (0, 255, 255).into(),
297            ..Default::default()
298        }
299        .with_component(
300            assets::LiteralComponent::new("Component_Interact").with_data([
301                (
302                    "Message",
303                    Box::new("You interacted!".to_string()) as Box<dyn AsBrdbValue>,
304                ),
305                ("ConsoleTag", Box::new("fixture_interact".to_string())),
306                ("bAllowNearbyInteraction", Box::new(false)),
307                ("bHiddenInteraction", Box::new(true)),
308                ("PromptCustomLabel", Box::new("Open Door".to_string())),
309            ]),
310        ),
311    );
312
313    // 4: Buffer (ticks) — Input/Output are WireValue; non-default counters
314    // plus a Number/Bool value pair.
315    world.bricks.push(
316        Brick {
317            position: (60, 0, 1).into(),
318            color: (128, 0, 128).into(),
319            asset: assets::components::BufferTicks::default().brick(),
320            ..Default::default()
321        }
322        .with_component(assets::components::BufferTicks {
323            current_ticks: 3,
324            ticks_to_wait: 10,
325            input: WireValue::Number(2.5),
326            output: WireValue::Bool(true),
327            ..Default::default()
328        }),
329    );
330
331    // 5: Blend gate — Expr_MathBlend's InputA/InputB are each a WireValue
332    // (here an f64 and an i64, showing the value is polymorphic per-port);
333    // Blend itself is a plain f64.
334    world.bricks.push(
335        Brick {
336            position: (80, 0, 1).into(),
337            color: (0, 128, 0).into(),
338            asset: assets::components::LogicGate::Blend.brick(),
339            ..Default::default()
340        }
341        .with_component(
342            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
343                (
344                    "InputA".into(),
345                    Box::new(WireValue::Number(10.0)) as Box<dyn AsBrdbValue>,
346                ),
347                ("InputB".into(), Box::new(WireValue::Int(7))),
348                ("Blend".into(), Box::new(0.75f64)),
349            ])),
350        ),
351    );
352
353    world
354}
355
356fn entities_world() -> World {
357    // Mirror of examples/write_entity.rs's floating sub-grid — the first
358    // grid added after the always-present main grid 1 gets persistent index
359    // 2, so it lands at Grids/2 — plus a couple of main-grid (Grids/1)
360    // bricks. Both grids are single-chunk; note the *outer* Grids/1 vs
361    // Grids/2 folder order comes from a HashMap<usize, UnsavedGrid> in the
362    // writer and is NOT guaranteed stable run-to-run (see stability notes).
363    //
364    // register_all_components() is required here (matching
365    // test_write_entity_save, NOT the plain write_entity.rs example): without
366    // it, Entity_DynamicBrickGrid's class name is never registered and the
367    // write fails with `UnknownType("Entity_DynamicBrickGrid")` — confirmed
368    // by running the crate's own unmodified write_entity example.
369    let mut world = World::new();
370    world.register_all_components();
371    world.meta.bundle.description = "Entity fixture".to_string();
372
373    world.bricks.push(Brick {
374        position: (0, 0, 6).into(),
375        color: (200, 50, 50).into(),
376        ..Default::default()
377    });
378    world.bricks.push(Brick {
379        position: (20, 0, 6).into(),
380        color: (50, 200, 50).into(),
381        ..Default::default()
382    });
383
384    world.add_brick_grid(
385        Entity {
386            frozen: true,
387            location: (0.0, 0.0, 40.0).into(),
388            ..Default::default()
389        },
390        [Brick {
391            position: (0, 0, 3).into(),
392            color: (0, 255, 0).into(),
393            ..Default::default()
394        }],
395    );
396
397    world
398}
399
400fn spawner_world() -> World {
401    // Prefab-embedding fixture: an outer prefab whose spawner gate references
402    // an inner single-brick prefab embedded at Prefabs/Uploads/<BLAKE3>.brz.
403    // Single grid, single chunk, one insertion-ordered prefab map entry —
404    // fully deterministic. The inner archive is written raw (no zstd) so the
405    // embedded bytes are cross-language reproducible.
406    let mut inner = World::new();
407    inner.meta.bundle.description = "Inner prefab".to_string();
408    inner.bricks.push(Brick {
409        position: (0, 0, 6).into(),
410        color: (255, 0, 0).into(),
411        ..Default::default()
412    });
413    inner.make_prefab();
414    let inner_bytes = {
415        let pending = inner.to_unsaved().unwrap().to_pending().unwrap();
416        let mut buf = Vec::new();
417        pending
418            .to_brz_data(None)
419            .unwrap()
420            .write(&mut buf, None)
421            .unwrap();
422        buf
423    };
424
425    let mut world = World::new();
426    world.register_all_components();
427    world.meta.bundle.description = "Spawner fixture".to_string();
428    let prefab_path = world.add_prefab(inner_bytes);
429    world.bricks.push(
430        Brick {
431            asset: brdb::BrickType::str("B_1x1_Gate_Exec_PrefabSpawner"),
432            position: (0, 0, 1).into(),
433            ..Default::default()
434        }
435        .with_component(
436            assets::LiteralComponent::new("BrickComponentType_Exec_PrefabSpawner")
437                .with_data([("Prefab", Box::new(prefab_path) as Box<dyn AsBrdbValue>)]),
438        ),
439    );
440    world.make_prefab();
441    world
442}
443
444/// `features_world` written in the Latest format.
445fn features_latest_world() -> World {
446    let mut world = features_world();
447    world.schema_format = BrdbSchemaFormat::Latest;
448    world
449}
450
451/// `entities_world` with the current build's schemas in the Latest format.
452fn entities_latest_world() -> World {
453    let mut world = World::new();
454    world.schema_format = BrdbSchemaFormat::Latest;
455    world.register_all_components();
456    world.meta.bundle.description = "Entity fixture".to_string();
457    world.bricks.push(Brick {
458        position: (0, 0, 6).into(),
459        color: (200, 50, 50).into(),
460        ..Default::default()
461    });
462    world.add_brick_grid(
463        Entity {
464            frozen: true,
465            location: (0.0, 0.0, 40.0).into(),
466            ..Default::default()
467        },
468        [Brick {
469            position: (0, 0, 3).into(),
470            color: (0, 255, 0).into(),
471            ..Default::default()
472        }],
473    );
474    world
475}
476
477/// Current-build components in the Latest format: WireValue fields, dynamic
478/// arrays/maps (typed and empty) and a dynamic enum, plus a wire.
479fn components_latest_world() -> World {
480    let mut world = World::new();
481    world.meta.bundle.description = "Latest component fixture".to_string();
482    let gate = |x: i32, asset: &'static str| Brick {
483        position: (x, 0, 1).into(),
484        asset: BrickType::str(asset),
485        ..Default::default()
486    };
487
488    // 1: Blend gate with WireValue inputs (f64 and i64 alternatives).
489    let (blend, blend_id) = gate(0, "B_1x1_Gate_Expr_MathBlend")
490        .with_component(
491            assets::components::LogicGate::Blend.component_with_overrides(HashMap::from([
492                (
493                    "InputA".into(),
494                    Box::new(WireValue::Number(1.5)) as Box<dyn AsBrdbValue>,
495                ),
496                ("InputB".into(), Box::new(WireValue::Int(-3))),
497                ("Blend".into(), Box::new(0.25f64)),
498            ])),
499        )
500        .with_id_split();
501    // 2: Buffer with Str / Bool alternatives.
502    let buffer =
503        gate(20, "B_1x1_Gate_BufferTicks").with_component(assets::components::BufferTicks {
504            ticks_to_wait: 4,
505            input: WireValue::Str("hello".into()),
506            output: WireValue::Bool(true),
507            buffered: WireValue::Vector {
508                x: 1.0,
509                y: -2.0,
510                z: 0.5,
511            },
512            ..Default::default()
513        });
514    // 3: Array variable holding i64 elements.
515    let array = gate(40, "B_1x1_Gate_Variable_Array").with_component(
516        assets::LiteralComponent::new("BrickComponentType_ArrayVar").with_data([(
517            "Value",
518            Box::new(BrdbDynamicArray::new(
519                "i64",
520                vec![BrdbValue::I64(7), BrdbValue::I64(300)],
521            )) as Box<dyn AsBrdbValue>,
522        )]),
523    );
524    // 4: Map variable from Str keys to f64 values.
525    let map = gate(60, "B_1x1_Gate_Variable_Map").with_component(
526        assets::LiteralComponent::new("BrickComponentType_MapVar").with_data([(
527            "Value",
528            Box::new(BrdbDynamicMap::new(
529                "Str",
530                "f64",
531                [(BrdbValue::String("k".into()), BrdbValue::F64(2.5))]
532                    .into_iter()
533                    .collect(),
534            )) as Box<dyn AsBrdbValue>,
535        )]),
536    );
537    // 5: Unset array variable: the default empty container.
538    let empty_array = gate(80, "B_1x1_Gate_Variable_Array")
539        .with_component(assets::LiteralComponent::new("BrickComponentType_ArrayVar"));
540    // 6: Integer to enum: a dynamic enum field.
541    let to_enum = gate(100, "B_1x1_Gate_Expr_IntegerToEnum").with_component(
542        assets::LiteralComponent::new("BrickComponentType_Expr_IntegerToEnum").with_data([
543            ("Input", Box::new(2i64) as Box<dyn AsBrdbValue>),
544            (
545                "TargetType",
546                Box::new(BrdbDynamicEnum::new("EBrickAxis", 0)),
547            ),
548        ]),
549    );
550    // 7: A rerouter fed by the blend gate.
551    let (reroute, reroute_id) = Brick {
552        position: (120, 0, 1).into(),
553        asset: assets::bricks::B_REROUTE,
554        ..Default::default()
555    }
556    .with_component(assets::components::Rerouter)
557    .with_id_split();
558
559    world.add_bricks([blend, buffer, array, map, empty_array, to_enum, reroute]);
560    world.add_wire_connection(
561        assets::components::LogicGate::Blend.output_of(blend_id),
562        assets::components::Rerouter::input_of(reroute_id),
563    );
564    // Embed only the structs these components use (what brs-js writes).
565    world.register_used_components();
566    world
567}
examples/write_prefab_spawner.rs (lines 69-76)
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}

Register an outer-microchip-brick ↔ inner-grid-entity pairing. The write path consumes this into ComponentChunkSoA.microchip_brick_indices / microchip_brick_grid_references. Most callers get this for free by going through add_microchip; use this directly only when constructing the pair manually.

Source

pub fn add_microchip( &mut self, position: Position, entity_location: Vector3f, plane_extent: IntVector, collapsed: bool, ) -> (usize, usize, (Entity, Vec<Brick>))

Build a microchip: spawns the outer microchip brick on the main grid, calls register_microchip_link with the pairing, and returns the outer brick’s id, the grid entity’s id, and the (Entity, Vec<Brick>) pair the caller populates before pushing to world.grids.

Typical usage:

ⓘ
let (chip_brick_id, chip_entity_id, mut inner) = world.add_microchip(
    Position { x: 0, y: 0, z: 6 },
    Vector3f { x: 0.0, y: 0.0, z: 40.0 },
    IntVector { x: 14, y: 14, z: 2 },
    true, // collapsed
);
inner.1.push(some_gate_brick);
world.grids.push(inner);

Trait Implementations§

Source§

impl Default for World

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for World

§

impl !UnwindSafe for World

§

impl Freeze for World

§

impl Send for World

§

impl Sync for World

§

impl Unpin for World

§

impl UnsafeUnpin for World

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<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.