all_is_cubes/block/modifier/
quote.rs1use crate::block;
2use crate::math::Rgb;
3use crate::universe;
4
5#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
9#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
10#[non_exhaustive]
11pub struct Quote {
12 pub suppress_ambient: bool,
14}
15
16impl Quote {
17 pub fn new() -> Self {
19 Self::default()
20 }
21
22 pub(in crate::block) fn evaluate(
23 &self,
24 value: block::MinEval,
25 filter: &block::EvalFilter<'_>,
26 ) -> Result<block::MinEval, block::InEvalError> {
27 let &Quote { suppress_ambient } = self;
29 let (
30 block::BlockAttributes {
31 display_name,
32 selectable,
33 inventory,
34 mut ambient_sound,
35 rotation_rule,
36 mut placement_action,
37 mut tick_action,
38 mut activation_action,
39 animation_hint,
40 },
41 mut voxels,
42 ) = value.into_parts();
43
44 if !filter.skip_eval {
45 tick_action = None;
47 placement_action = None;
48 activation_action = None;
49
50 if suppress_ambient {
52 block::Budget::decrement_voxels(&filter.budget, voxels.count())?;
53 for voxel in voxels.as_vol_mut().as_linear_mut().iter_mut() {
54 voxel.emission = Rgb::ZERO;
55 }
56
57 ambient_sound = crate::sound::Ambient::SILENT;
58 }
59 }
60
61 Ok(block::MinEval::new(
62 block::BlockAttributes {
63 display_name,
64 selectable,
65 inventory,
66 ambient_sound,
67 rotation_rule,
68 placement_action,
69 tick_action,
70 activation_action,
71 animation_hint,
72 },
73 voxels,
74 ))
75 }
76}
77
78impl From<Quote> for block::Modifier {
79 fn from(value: Quote) -> Self {
80 block::Modifier::Quote(value)
81 }
82}
83
84impl universe::VisitHandles for Quote {
85 fn visit_handles(&self, _visitor: &mut dyn universe::HandleVisitor) {
86 let Quote {
87 suppress_ambient: _,
88 } = self;
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use crate::block::Block;
96 use crate::math::Rgba;
97 use crate::{op, time};
98 use pretty_assertions::assert_eq;
99
100 #[test]
101 fn quote_evaluation() {
102 let light = Rgb::new(1.0, 2.0, 3.0);
103
104 let block = Block::builder()
105 .color(Rgba::WHITE)
106 .light_emission(light)
107 .placement_action(block::PlacementAction {
108 operation: op::Operation::Become(block::AIR),
109 in_front: true,
110 })
111 .tick_action(block::TickAction {
112 operation: op::Operation::Become(block::AIR),
113 schedule: time::Schedule::EVERY_TICK,
114 })
115 .activation_action(op::Operation::Become(block::AIR))
116 .build();
117
118 assert_eq!(
119 eval_without_metadata(&block.clone().with_modifier(Quote {
120 suppress_ambient: false,
121 })),
122 eval_without_metadata(
123 &Block::builder().color(Rgba::WHITE).light_emission(light).build()
124 ),
125 "suppress_ambient = false"
126 );
127
128 assert_eq!(
129 eval_without_metadata(&block.with_modifier(Quote {
130 suppress_ambient: true,
131 })),
132 eval_without_metadata(&Block::builder().color(Rgba::WHITE).build()),
133 "suppress_ambient = true"
134 );
135 }
136
137 #[inline(never)]
141 fn eval_without_metadata(block: &Block) -> (block::BlockAttributes, block::Evoxels) {
142 let evaluated = block.evaluate(universe::ReadTicket::stub()).unwrap();
143 (evaluated.attributes().clone(), evaluated.voxels().clone())
144 }
145}