steel_core/block_entity/entities/
comparator.rs1use std::sync::Weak;
4
5use simdnbt::borrow::{BaseNbtCompound as BorrowedNbtCompound, NbtCompound as NbtCompoundView};
6use simdnbt::owned::NbtCompound;
7use steel_registry::vanilla_block_entity_types;
8use steel_utils::{BlockPos, BlockStateId, DowncastType, DowncastTypeKey, locks::SyncMutex};
9
10use crate::block_entity::{BlockEntity, BlockEntityBase};
11use crate::world::World;
12
13struct ComparatorState {
14 output_signal: i32,
15}
16
17pub struct ComparatorBlockEntity {
19 base: BlockEntityBase,
20 state: SyncMutex<ComparatorState>,
21}
22
23unsafe impl DowncastType for ComparatorBlockEntity {
25 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:block_entity/comparator");
26}
27
28impl ComparatorBlockEntity {
29 #[must_use]
31 pub fn new(world: Weak<World>, pos: BlockPos, state: BlockStateId) -> Self {
32 Self {
33 base: BlockEntityBase::new(&vanilla_block_entity_types::COMPARATOR, world, pos, state),
34 state: SyncMutex::new(ComparatorState { output_signal: 0 }),
35 }
36 }
37
38 #[must_use]
40 pub fn output_signal(&self) -> i32 {
41 self.state.lock().output_signal
42 }
43
44 pub fn set_output_signal(&self, output_signal: i32) {
46 self.state.lock().output_signal = output_signal;
47 }
48}
49
50impl BlockEntity for ComparatorBlockEntity {
51 fn base(&self) -> &BlockEntityBase {
52 &self.base
53 }
54
55 fn load_additional(&self, nbt: &BorrowedNbtCompound<'_>) {
56 let nbt: NbtCompoundView<'_, '_> = nbt.into();
57 self.state.lock().output_signal = nbt.int("OutputSignal").unwrap_or(0);
58 }
59
60 fn save_additional(&self, nbt: &mut NbtCompound) {
61 nbt.insert("OutputSignal", self.output_signal());
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use std::io::Cursor;
68
69 use simdnbt::borrow::read_compound as read_borrowed_compound;
70 use steel_registry::{init_vanilla_registry, vanilla_blocks};
71
72 use super::*;
73
74 fn comparator() -> ComparatorBlockEntity {
75 init_vanilla_registry();
76 ComparatorBlockEntity::new(
77 Weak::new(),
78 BlockPos::new(4, 65, -9),
79 vanilla_blocks::COMPARATOR.default_state(),
80 )
81 }
82
83 #[test]
84 fn output_signal_round_trips_with_vanilla_nbt_key() {
85 let source = comparator();
86 source.set_output_signal(11);
87 let mut nbt = NbtCompound::new();
88 source.save_additional(&mut nbt);
89 assert_eq!(nbt.int("OutputSignal"), Some(11));
90
91 let mut bytes = Vec::new();
92 nbt.write(&mut bytes);
93 let borrowed = read_borrowed_compound(&mut Cursor::new(bytes.as_slice()))
94 .expect("test NBT should reborrow");
95 let loaded = comparator();
96 loaded.load_additional(&borrowed);
97 assert_eq!(loaded.output_signal(), 11);
98 }
99
100 #[test]
101 fn missing_output_signal_loads_vanilla_default() {
102 let nbt = NbtCompound::new();
103 let mut bytes = Vec::new();
104 nbt.write(&mut bytes);
105 let borrowed = read_borrowed_compound(&mut Cursor::new(bytes.as_slice()))
106 .expect("test NBT should reborrow");
107 let loaded = comparator();
108 loaded.set_output_signal(15);
109 loaded.load_additional(&borrowed);
110 assert_eq!(loaded.output_signal(), 0);
111 }
112}