Skip to content

Commit

Permalink
Add inventory configuration block attribute.
Browse files Browse the repository at this point in the history
`inv::InvInBlock` is now public, but doesn't have accessors yet
so it still can’t actually be properly customized.
  • Loading branch information
kpreid committed Jul 17, 2024
1 parent c5b30bb commit 966fb8b
Show file tree
Hide file tree
Showing 13 changed files with 352 additions and 43 deletions.
13 changes: 13 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Changelog

## Unrelased

### Added

- `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.

### Changed

### Removed

## 0.8.0 (2024-07-08)

### Added
Expand Down
8 changes: 8 additions & 0 deletions all-is-cubes-content/src/city/exhibits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -809,9 +809,17 @@ fn INVENTORY(ctx: Context<'_>) {
&AIR
}
})?
.inventory_config(inv::InvInBlock::new_placeholder())
.build_txn(&mut txn);
// TODO: awkward that we have to evaluate
let config = inventory_display_block
.evaluate()
.unwrap()
.attributes
.inventory;

let has_items_block = inventory_display_block.with_inventory(
&config,
[
inv::Tool::Block(demo_blocks[DemoBlocks::ExhibitBackground].clone()).into(),
inv::Tool::Block(color_block!(Rgb::UNIFORM_LUMINANCE_RED)).into(),
Expand Down
23 changes: 15 additions & 8 deletions all-is-cubes/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use alloc::sync::Arc;
use alloc::vec::Vec;
use core::fmt;

use crate::inv::{self, InvInBlock};
use crate::inv;
use crate::listen::{Listen as _, Listener};
use crate::math::{GridAab, GridCoordinate, GridPoint, GridRotation, GridVector, Rgb, Rgba, Vol};
use crate::space::{SetCubeError, Space, SpaceChange};
Expand Down Expand Up @@ -354,18 +354,25 @@ impl Block {

/// Given a block that does not yet have an [`Modifier::Inventory`], add it.
///
/// The size of the added inventory is the maximum of the size set by [`InvInBlock`]
/// The size of the added inventory is the maximum of the size set by [`config`]
/// (which should normally be from the evaluated [`BlockAttributes`] of this block)
/// and the size of `contents`.
///
/// TODO: It is not yet decided what happens when this is called on a block which already
/// has an inventory. Currently, it just attaches another modifier.
//---
// TODO(inventory): Decide what happens when this is called on a block which
// already has an inventory. Currently, it just attaches another modifier.
//
// TODO(inventory): Decide what happens when `config.size == 0`.
// Should we refrain from adding the modifier?
#[must_use]
pub fn with_inventory(self, contents: impl Iterator<Item = inv::Slot>) -> Block {
pub fn with_inventory(
self,
config: &inv::InvInBlock,
contents: impl Iterator<Item = inv::Slot>,
) -> Block {
let inventory = inv::Inventory::from_slots(
itertools::Itertools::zip_longest(
contents,
// TODO(inventory): InvInBlock should be part of block attributes
core::iter::repeat(inv::Slot::Empty).take(InvInBlock::default().size),
core::iter::repeat(inv::Slot::Empty).take(config.size),
)
.map(|z| z.into_left())
.collect::<Box<[inv::Slot]>>(),
Expand Down
22 changes: 20 additions & 2 deletions all-is-cubes/src/block/attributes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ use core::{fmt, ops};

use arcstr::ArcStr;

use crate::inv::InvInBlock;
use crate::math::{Face6, GridRotation};
use crate::op::Operation;

#[cfg(doc)]
use crate::{
block::{Block, BlockDef, Primitive},
block::{Block, BlockDef, Modifier, Primitive},
space::Space,
time::TickSchedule,
};
Expand All @@ -36,6 +37,10 @@ pub struct BlockAttributes {
/// The default value is `true`.
pub selectable: bool,

/// Definition of, if this block has an attached [`Modifier::Inventory`],
/// what size and rendering it has.
pub inventory: InvInBlock,

/// Rule about how this block should be rotated, or not, when placed in a [`Space`] by
/// some agent not otherwise specifying rotation.
///
Expand Down Expand Up @@ -70,6 +75,7 @@ impl fmt::Debug for BlockAttributes {
let Self {
display_name,
selectable,
inventory,
rotation_rule,
tick_action,
activation_action,
Expand All @@ -84,6 +90,9 @@ impl fmt::Debug for BlockAttributes {
if *selectable != Self::DEFAULT_REF.selectable {
s.field("selectable", selectable);
}
if *inventory != Self::DEFAULT_REF.inventory {
s.field("inventory", inventory);
}
if *rotation_rule != Self::DEFAULT_REF.rotation_rule {
s.field("rotation_rule", rotation_rule);
}
Expand All @@ -105,6 +114,7 @@ impl BlockAttributes {
const DEFAULT: Self = BlockAttributes {
display_name: arcstr::literal!(""),
selectable: true,
inventory: InvInBlock::EMPTY,
rotation_rule: RotationPlacementRule::Never,
tick_action: None,
activation_action: None,
Expand All @@ -127,13 +137,15 @@ impl BlockAttributes {
let Self {
display_name: _,
selectable: _,
inventory,
rotation_rule,
tick_action,
activation_action,
animation_hint: _,
} = self;

rotation_rule.rotationally_symmetric()
inventory.rotationally_symmetric()
&& rotation_rule.rotationally_symmetric()
&& !tick_action
.as_ref()
.is_some_and(|a| !a.rotationally_symmetric())
Expand All @@ -146,6 +158,7 @@ impl BlockAttributes {
let Self {
display_name,
selectable,
inventory,
rotation_rule,
mut tick_action,
mut activation_action,
Expand All @@ -162,6 +175,7 @@ impl BlockAttributes {
Self {
display_name,
selectable,
inventory: inventory.rotate(rotation),
rotation_rule: rotation_rule.rotate(rotation),
tick_action,
activation_action,
Expand All @@ -186,6 +200,7 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockAttributes {
Ok(BlockAttributes {
display_name: u.arbitrary::<alloc::string::String>()?.into(),
selectable: u.arbitrary()?,
inventory: u.arbitrary()?,
rotation_rule: u.arbitrary()?,
tick_action: u.arbitrary()?,
activation_action: u.arbitrary()?,
Expand All @@ -197,6 +212,7 @@ impl<'a> arbitrary::Arbitrary<'a> for BlockAttributes {
arbitrary::size_hint::and_all(&[
alloc::string::String::size_hint(depth),
bool::size_hint(depth),
InvInBlock::size_hint(depth),
RotationPlacementRule::size_hint(depth),
TickAction::size_hint(depth),
AnimationHint::size_hint(depth),
Expand All @@ -209,11 +225,13 @@ impl crate::universe::VisitHandles for BlockAttributes {
let Self {
display_name: _,
selectable: _,
inventory,
rotation_rule: _,
tick_action,
activation_action,
animation_hint: _,
} = self;
inventory.visit_handles(visitor);
tick_action.visit_handles(visitor);
activation_action.visit_handles(visitor);
}
Expand Down
12 changes: 11 additions & 1 deletion all-is-cubes/src/block/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use crate::block::{
AnimationHint, Atom, Block, BlockAttributes, BlockCollision, BlockParts, BlockPtr, Modifier,
Primitive, Resolution, RotationPlacementRule, AIR,
};
use crate::inv;
use crate::math::{Cube, GridAab, GridPoint, Rgb, Rgba};
use crate::space::{SetCubeError, Space};
use crate::transaction::{self, Merge, Transaction};
Expand Down Expand Up @@ -91,6 +92,12 @@ impl<P, Txn> BlockBuilder<P, Txn> {
self
}

/// Sets the value for [`BlockAttributes::inventory`].
pub fn inventory_config(mut self, value: inv::InvInBlock) -> Self {
self.attributes.inventory = value;
self
}

/// Sets the value for [`BlockAttributes::rotation_rule`].
pub const fn rotation_rule(mut self, value: RotationPlacementRule) -> Self {
self.attributes.rotation_rule = value;
Expand Down Expand Up @@ -446,13 +453,15 @@ mod tests {
fn every_field_nondefault() {
let color = Rgba::new(0.1, 0.2, 0.3, 0.4);
let emission = Rgb::new(0.1, 3.0, 0.1);
let inventory = inv::InvInBlock::new_placeholder();
let rotation_rule = RotationPlacementRule::Attach { by: Face6::NZ };
let tick_action = Some(TickAction::from(Operation::Become(AIR)));
let activation_action = Some(Operation::Become(color_block!(1.0, 1.0, 1.0)));
assert_eq!(
Block::builder()
.color(color)
.display_name("hello world")
.inventory_config(inventory.clone())
.collision(BlockCollision::None)
.rotation_rule(rotation_rule)
.selectable(false)
Expand All @@ -464,8 +473,9 @@ mod tests {
Block::from(Atom {
attributes: BlockAttributes {
display_name: "hello world".into(),
rotation_rule,
selectable: false,
inventory,
rotation_rule,
tick_action,
activation_action,
animation_hint: AnimationHint::replacement(block::AnimationChange::Shape),
Expand Down
5 changes: 5 additions & 0 deletions all-is-cubes/src/block/eval/evaluated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,7 @@ pub(in crate::block) const AIR_EVALUATED_MIN: MinEval = MinEval {
const AIR_ATTRIBUTES: BlockAttributes = BlockAttributes {
display_name: arcstr::literal!("<air>"),
selectable: false,
inventory: crate::inv::InvInBlock::EMPTY,
rotation_rule: block::RotationPlacementRule::Never,
tick_action: None,
activation_action: None,
Expand Down Expand Up @@ -353,6 +354,7 @@ impl PartialEq for EvKey {
BlockAttributes {
ref display_name,
selectable,
ref inventory,
rotation_rule,
ref tick_action,
ref activation_action,
Expand All @@ -366,6 +368,7 @@ impl PartialEq for EvKey {
display_name.as_ptr(),
other.attributes.display_name.as_ptr(),
) && selectable == other.attributes.selectable
&& *inventory == other.attributes.inventory
&& rotation_rule == other.attributes.rotation_rule
&& *tick_action == other.attributes.tick_action
&& *activation_action == other.attributes.activation_action
Expand All @@ -381,6 +384,7 @@ impl core::hash::Hash for EvKey {
BlockAttributes {
ref display_name,
selectable,
ref inventory,
rotation_rule,
ref tick_action,
ref activation_action,
Expand All @@ -391,6 +395,7 @@ impl core::hash::Hash for EvKey {

display_name.as_ptr().hash(state);
selectable.hash(state);
inventory.hash(state);
rotation_rule.hash(state);
tick_action.hash(state);
activation_action.hash(state);
Expand Down
6 changes: 4 additions & 2 deletions all-is-cubes/src/block/modifier/composite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ fn evaluate_composition(
let attributes = block::BlockAttributes {
display_name: dst_att.display_name, // TODO merge
selectable: src_att.selectable | dst_att.selectable,
inventory: src_att.inventory.concatenate(dst_att.inventory),
rotation_rule: dst_att.rotation_rule, // TODO merge
tick_action: dst_att.tick_action, // TODO: merge
activation_action: operator.blend_operations(
Expand Down Expand Up @@ -448,8 +449,9 @@ pub(in crate::block) fn render_inventory(
return Ok(input);
}

// TODO(inventory): InvInBlock should be part of block attributes
let config = crate::inv::InvInBlock::default();
// TODO(inventory): clone necessary to avoid a borrow conflict
let config = input.attributes.inventory.clone();

for (slot_index, icon_position) in config.icon_positions() {
let Some(placed_icon_bounds) = GridAab::from_lower_size(
icon_position,
Expand Down
2 changes: 1 addition & 1 deletion all-is-cubes/src/inv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ pub use icons::*;
mod inventory;
pub use inventory::*;
mod inv_in_block;
pub use inv_in_block::InvInBlock;
pub use inv_in_block::*;
mod tool;
pub use tool::*;

Expand Down
Loading

0 comments on commit 966fb8b

Please sign in to comment.