steel_core/block_entity/entities/
skull.rs1use crate::behavior::blocks::{SkullData, SkullType};
2use crate::behavior::skull_types;
3use crate::block_entity::{BlockEntity, BlockEntityBase};
4use crate::world::World;
5use simdnbt::borrow::{BaseNbtCompound as BorrowedNbtCompound, NbtCompound as NbtCompoundView};
6use simdnbt::owned::NbtCompound;
7use simdnbt::{FromNbtTag, ToNbtTag};
8use std::sync::Weak;
9use steel_registry::blocks::block_state_ext::BlockStateExt;
10use steel_registry::data_components::DataComponentPatch;
11use steel_registry::item_stack::ItemStack;
12use steel_registry::{REGISTRY, ResolvableProfile, vanilla_block_entity_types};
13use steel_utils::locks::SyncMutex;
14use steel_utils::{BlockPos, BlockStateId, DowncastType, DowncastTypeKey, Identifier};
15use text_components::TextComponent;
16
17const PROFILE_NBT_KEY: &str = "profile";
18const NOTE_BLOCK_SOUND_NBT_KEY: &str = "note_block_sound";
19const CUSTOM_NAME_NBT_KEY: &str = "custom_name";
20
21pub struct SkullBlockEntity {
25 base: BlockEntityBase,
26 state: SyncMutex<SkullData>,
27}
28
29unsafe impl DowncastType for SkullBlockEntity {
31 const TYPE_KEY: DowncastTypeKey = DowncastTypeKey::new("steel:block_entity/skull");
32}
33
34impl SkullBlockEntity {
35 #[must_use]
37 pub fn new(level: Weak<World>, pos: BlockPos, state: BlockStateId) -> Self {
38 Self {
39 base: BlockEntityBase::new(&vanilla_block_entity_types::SKULL, level, pos, state),
40 state: SyncMutex::new(SkullData::default()),
41 }
42 }
43
44 pub fn get_note_block_sound(&self) -> Option<Identifier> {
46 self.state.lock().note_block_sound.clone()
47 }
48
49 #[must_use]
51 pub fn data(&self) -> SkullData {
52 self.state.lock().clone()
53 }
54
55 pub fn set_data(&self, data: SkullData) {
57 {
58 let mut state = self.state.lock();
59 if *state == data {
60 return;
61 }
62 *state = data;
63 }
64 self.set_changed();
65 if let Some(world) = self.get_level() {
66 world.send_block_updated(self.base.pos);
67 }
68 }
69
70 pub fn skull_as_picked_item(&self, state: BlockStateId) -> ItemStack {
72 let patch = self.state.lock().component_patch();
73 Self::skull_as_item(state, patch)
74 }
75
76 pub fn skull_as_dropped_item(&self, state: BlockStateId) -> ItemStack {
79 let is_player_head = SkullType::from_block(state.get_block()) == Some(&skull_types::PLAYER);
80 let data = self.state.lock();
81 let patch = if is_player_head {
82 data.component_patch()
83 } else {
84 data.custom_name_patch()
85 };
86 drop(data);
87 Self::skull_as_item(state, patch)
88 }
89
90 fn skull_as_item(state: BlockStateId, patch: DataComponentPatch) -> ItemStack {
91 let block_item = REGISTRY.items.by_block(state.get_block());
92 ItemStack::with_count_and_patch(block_item, 1, patch)
93 }
94}
95
96impl BlockEntity for SkullBlockEntity {
97 fn base(&self) -> &BlockEntityBase {
98 &self.base
99 }
100
101 fn load_additional(&self, nbt: &BorrowedNbtCompound<'_>) {
102 let nbt: NbtCompoundView<'_, '_> = nbt.into();
103 let mut state = self.state.lock();
104
105 state.owner =
106 ResolvableProfile::from_optional_nbt_tag(nbt.get(PROFILE_NBT_KEY)).unwrap_or_default();
107 state.note_block_sound =
108 Identifier::from_optional_nbt_tag(nbt.get(NOTE_BLOCK_SOUND_NBT_KEY))
109 .unwrap_or_default();
110 state.custom_name =
111 TextComponent::from_optional_nbt_tag(nbt.get(CUSTOM_NAME_NBT_KEY)).unwrap_or_default();
112 }
113
114 fn save_additional(&self, nbt: &mut NbtCompound) {
115 let state = self.state.lock();
116
117 if let Some(profile) = state.owner.clone().to_optional_nbt_tag() {
118 nbt.insert(PROFILE_NBT_KEY, profile);
119 }
120
121 if let Some(sound) = state.note_block_sound.clone().to_optional_nbt_tag() {
122 nbt.insert(NOTE_BLOCK_SOUND_NBT_KEY, sound);
123 }
124
125 if let Some(name) = state.custom_name.clone().to_optional_nbt_tag() {
126 nbt.insert(CUSTOM_NAME_NBT_KEY, name);
127 }
128 }
129
130 fn get_update_tag(&self) -> Option<NbtCompound> {
131 Some(self.save_custom_only())
132 }
133
134 fn apply_components_from_item_stack(&self, item: &ItemStack) {
135 let mut state = self.state.lock();
136 *state = SkullData::from_item(item);
137 }
138}