Skip to content

Commit

Permalink
Move BlockAttributes storage out of Primitive.
Browse files Browse the repository at this point in the history
Motivation:

* Many blocks have all default attributes. This way, the primitive need
  not store all attributes (is smaller in memory), is conceptually
  simpler, and leans less heavily on “default values aren’t serialized”.
* Sometimes you want to set attributes on an already-modified block,
  like a `Composite` of several more basic parts.
* `BlockAttributes` itself is an inelegant bundle of many different
  concerns, which has needed to change incompatibly. (For example, light
  emission used to be an attribute and now is strictly per-voxel.) After
  this change, we can, if we choose, completely hide or remove
  `BlockAttributes`; we would replace creating it with a bunch of
  modifiers which override individual attributes, and replace reading
  it with individual methods on `EvaluatedBlock`.
  • Loading branch information
kpreid committed Aug 19, 2024
1 parent 1e55bd4 commit ec4813f
Show file tree
Hide file tree
Showing 24 changed files with 379 additions and 298 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
- `all-is-cubes` library:
- Block inventories are now more functional.
- `block::Block::with_inventory` attaches inventory to a block.
- `inv::InvInBlock`, stored in `block::BlockAtributes::inventory`, describes the size and rendering such inventories should have.
- `inv::InvInBlock`, stored in `block::BlockAttributes::inventory`, describes the size and rendering such inventories should have.
- `block::Modifier::Attributes` allows overriding block attributes.

### Changed

Expand All @@ -22,6 +23,10 @@

### Removed

- `all-is-cubes` library:
- `block::Primitive` no longer contains `BlockAttributes` in any of its variants.
The new means of specifying attributes is `block::Modifier::Attributes`.

## 0.8.0 (2024-07-08)

### Added
Expand Down
17 changes: 4 additions & 13 deletions all-is-cubes-content/src/blocks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use exhaust::Exhaust;
use rand::{Rng as _, SeedableRng as _};

use all_is_cubes::block::{
self, AnimationHint, Atom, Block, BlockCollision, BlockDefTransaction, Primitive,
self, AnimationHint, Block, BlockCollision, BlockDefTransaction, Primitive,
Resolution::*, RotationPlacementRule, TickAction, AIR,
};
use all_is_cubes::color_block;
Expand Down Expand Up @@ -500,10 +500,7 @@ pub async fn install_demo_blocks(
// Join up blinker blocks
for state in bool::exhaust() {
modify_def(&provider_for_patch[BecomeBlinker(state)], |block| {
let Primitive::Atom(Atom { attributes, .. }) = block.primitive_mut() else {
panic!("blinker not atom");
};
attributes.tick_action = Some(TickAction {
block.freezing_get_attributes_mut().tick_action = Some(TickAction {
operation: Operation::Become(provider_for_patch[BecomeBlinker(!state)].clone()),
schedule: time::Schedule::from_period(NonZeroU16::new(60).unwrap()),
});
Expand All @@ -514,10 +511,7 @@ pub async fn install_demo_blocks(
for state in bool::exhaust() {
for ctor in [Lamp, Sconce] {
modify_def(&provider_for_patch[ctor(state)], |block| {
let Primitive::Recur { attributes, .. } = block.primitive_mut() else {
panic!("lamp not recur");
};
attributes.activation_action =
block.freezing_get_attributes_mut().activation_action =
Some(Operation::Become(provider_for_patch[ctor(!state)].clone()));
});
}
Expand All @@ -526,9 +520,6 @@ pub async fn install_demo_blocks(
// Join up explosion blocks
for i in i8::exhaust() {
modify_def(&provider_for_patch[Explosion(i)], |block| {
let Primitive::Recur { attributes, .. } = block.primitive_mut() else {
panic!("explosion not atom");
};
let neighbor_ops: Arc<[(Cube, Operation)]> = if i > 22 {
// Expire because we're invisible by now
[(Cube::ORIGIN, Operation::Become(AIR))].into()
Expand Down Expand Up @@ -574,7 +565,7 @@ pub async fn install_demo_blocks(
[(Cube::ORIGIN, next.clone())].into()
}
};
attributes.tick_action = Some(TickAction {
block.freezing_get_attributes_mut().tick_action = Some(TickAction {
operation: Operation::Neighbors(neighbor_ops),
schedule: time::Schedule::from_period(NonZeroU16::new(2).unwrap()),
});
Expand Down
5 changes: 3 additions & 2 deletions all-is-cubes-content/src/city.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,10 +534,11 @@ fn place_one_exhibit<I: Instant>(
bounds_for_info_voxels,
universe.insert_anonymous(exhibit_info_space),
info_resolution,
BlockAttributes {
[BlockAttributes {
display_name: "Exhibit Name".into(),
..Default::default()
},
}
.into()],
))),
],
});
Expand Down
10 changes: 6 additions & 4 deletions all-is-cubes-content/src/city/exhibits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -284,11 +284,13 @@ fn KNOT(ctx: Context<'_>) {
})?;
let space = space_to_blocks(
resolution,
BlockAttributes {
display_name: ctx.exhibit.name.into(),
..BlockAttributes::default()
},
txn.insert_anonymous(drawing_space),
&mut |block| {
block.with_modifier(BlockAttributes {
display_name: ctx.exhibit.name.into(),
..BlockAttributes::default()
})
},
)?;
Ok((space, txn))
}
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes-content/src/menu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use alloc::vec::Vec;
use strum::IntoEnumIterator;

use all_is_cubes::arcstr;
use all_is_cubes::block::{BlockAttributes, Resolution};
use all_is_cubes::block::Resolution;
use all_is_cubes::character::Spawn;
use all_is_cubes::content::palette;
use all_is_cubes::euclid::Vector3D;
Expand Down Expand Up @@ -39,7 +39,7 @@ pub(crate) async fn template_menu(
logo_text_space.bounds(),
universe.insert_anonymous(logo_text_space),
Resolution::R8,
BlockAttributes::default(),
[],
);

let mut vertical_widgets: Vec<vui::WidgetTree> = Vec::with_capacity(10);
Expand Down
11 changes: 5 additions & 6 deletions all-is-cubes-ui/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ fn inspect_primitive(primitive: &block::Primitive) -> vui::WidgetTree {
let (name, details): (ArcStr, vui::WidgetTree) = match primitive {
block::Primitive::Indirect(block_def) => (literal!("Indirect"), inspect_handle(block_def)),
block::Primitive::Atom(block::Atom {
attributes,
color,
emission,
collision,
Expand All @@ -72,14 +71,12 @@ fn inspect_primitive(primitive: &block::Primitive) -> vui::WidgetTree {
"\
Color: {color:?}\n\
Emission: {emission:?}\n\
Collision: {collision:?}\n\
Attributes: {attributes:#?}\
Collision: {collision:?}\
"
))],
}),
),
block::Primitive::Recur {
attributes,
space,
offset,
resolution,
Expand All @@ -92,8 +89,7 @@ fn inspect_primitive(primitive: &block::Primitive) -> vui::WidgetTree {
paragraph(arcstr::format!(
"\
Resolution: {resolution}\n\
Offset: {offset:?}\n\
Attributes: {attributes:#?}\
Offset: {offset:?}\
"
)),
],
Expand Down Expand Up @@ -142,6 +138,9 @@ fn inspect_modifier(block: &Block, modifier_index: usize) -> vui::WidgetTree {
.truncate(modifier_index + 1);

let (name, details) = match modifier {
block::Modifier::Attributes(a) => {
(literal!("Attributes"), paragraph(arcstr::format!("{a:?}")))
}
block::Modifier::Quote(q) => (literal!("Quote"), paragraph(arcstr::format!("{q:?}"))),
block::Modifier::Rotate(rotation) => (
literal!("Rotate"),
Expand Down
4 changes: 2 additions & 2 deletions all-is-cubes-ui/src/vui/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use alloc::sync::Arc;

use all_is_cubes::arcstr::ArcStr;
use all_is_cubes::block::{text, AIR};
use all_is_cubes::block::{Block, BlockAttributes, Resolution};
use all_is_cubes::block::{Block, Resolution};
use all_is_cubes::color_block;
use all_is_cubes::content::palette;
use all_is_cubes::euclid::{size2, Size2D};
Expand Down Expand Up @@ -312,7 +312,7 @@ pub(crate) mod parts {
space.bounds(),
universe.insert_anonymous(space),
resolution,
BlockAttributes::default(),
[],
)))
}

Expand Down
37 changes: 16 additions & 21 deletions all-is-cubes-ui/src/vui/widgets/voxels.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alloc::sync::Arc;

use all_is_cubes::block::{Block, BlockAttributes, Primitive, Resolution};
use all_is_cubes::block::{self, Block, Primitive, Resolution};
use all_is_cubes::euclid::Size3D;
use all_is_cubes::math::{GridAab, GridMatrix, GridPoint, GridSizeCoord, GridVector};
use all_is_cubes::space::{Space, SpaceTransaction};
Expand All @@ -17,7 +17,7 @@ pub struct Voxels {
space: Handle<Space>,
region: GridAab,
scale: Resolution,
block_attributes: BlockAttributes,
modifiers: Vec<block::Modifier>,
}

impl Voxels {
Expand All @@ -26,19 +26,19 @@ impl Voxels {
/// When the `region`'s dimensions are not multiples of `scale`, their alignment within the
/// block grid will be determined by the layout gravity. Note that areas of `space` outside of
/// `region` may be displayed in that case.
pub const fn new(
pub fn new(
region: GridAab,
space: Handle<Space>,
scale: Resolution,
block_attributes: BlockAttributes,
modifiers: impl IntoIterator<Item = block::Modifier>,
) -> Self {
// Design note: We could take `region` from `space` but that'd require locking it,
// and the caller is very likely to already have that information.
Self {
space,
region,
scale,
block_attributes,
modifiers: modifiers.into_iter().collect(),
}
}
}
Expand Down Expand Up @@ -92,15 +92,15 @@ impl vui::Widget for Voxels {

let mut txn = SpaceTransaction::default();
for cube in position.bounds.interior_iter() {
txn.at(cube)
.overwrite(Block::from_primitive(Primitive::Recur {
attributes: self.block_attributes.clone(),
offset: block_to_voxels_transform
.transform_cube(cube)
.lower_bounds(),
resolution: self.scale,
space: self.space.clone(),
}));
let mut block = Block::from_primitive(Primitive::Recur {
offset: block_to_voxels_transform
.transform_cube(cube)
.lower_bounds(),
resolution: self.scale,
space: self.space.clone(),
});
block.modifiers_mut().clone_from(&self.modifiers);
txn.at(cube).overwrite(block);
}
super::OneshotController::new(txn)
}
Expand All @@ -119,7 +119,6 @@ mod tests {
fn test_voxels_widget(
voxel_space_bounds: GridAab,
grant: vui::LayoutGrant,
attributes: BlockAttributes,
) -> (Option<GridAab>, Space) {
let mut universe = Universe::new();
instantiate_widget(
Expand All @@ -128,7 +127,7 @@ mod tests {
voxel_space_bounds,
universe.insert_anonymous(Space::builder(voxel_space_bounds).build()),
R8,
attributes,
[],
),
)
}
Expand All @@ -141,7 +140,6 @@ mod tests {
let _output = test_voxels_widget(
v_space_bounds,
vui::LayoutGrant::new(GridAab::single_cube(output_origin)),
BlockAttributes::default(),
);
// TODO assertions about resulting blocks
}
Expand All @@ -158,16 +156,14 @@ mod tests {
bounds: GridAab::from_lower_size(output_origin, [3, 3, 3]),
gravity: Vector3D::new(Align::Low, Align::Center, Align::High),
};
let (output_bounds, output) =
test_voxels_widget(v_space_bounds, grant, BlockAttributes::default());
let (output_bounds, output) = test_voxels_widget(v_space_bounds, grant);
assert_eq!(
output_bounds.unwrap(),
GridAab::from_lower_size([100, 101, 101], [1, 1, 2])
);
// Expect two adjacent recursive blocks
match *output[[100, 101, 101]].primitive() {
Primitive::Recur {
attributes: _,
offset,
resolution,
space: _,
Expand All @@ -179,7 +175,6 @@ mod tests {
}
match *output[[100, 101, 102]].primitive() {
Primitive::Recur {
attributes: _,
offset,
resolution,
space: _,
Expand Down
Loading

0 comments on commit ec4813f

Please sign in to comment.