1- use std:: {
2- any:: Any ,
3- array:: from_fn,
4- pin:: Pin ,
5- sync:: {
6- Arc ,
7- atomic:: { AtomicBool , Ordering } ,
8- } ,
9- } ;
1+ use std:: sync:: { Arc , atomic:: AtomicBool } ;
2+
3+ use pumpkin_data:: block_properties:: BlockProperties ;
4+ use pumpkin_util:: math:: position:: BlockPos ;
105
11- use pumpkin_data:: {
12- Block , HorizontalFacingExt ,
13- block_properties:: { BlockProperties , ChestLikeProperties , ChestType } ,
14- sound:: { Sound , SoundCategory } ,
15- } ;
16- use pumpkin_nbt:: compound:: NbtCompound ;
17- use pumpkin_util:: {
18- math:: { position:: BlockPos , vector3:: Vector3 } ,
19- random:: { RandomImpl , get_seed, xoroshiro128:: Xoroshiro } ,
20- } ;
216use tokio:: sync:: Mutex ;
227
238use crate :: {
24- block:: viewer:: { ViewerCountListener , ViewerCountTracker , ViewerFuture } ,
25- inventory :: { Clearable , Inventory , InventoryFuture , split_stack } ,
9+ block:: viewer:: ViewerCountTracker , impl_block_entity_for_chest , impl_chest_helper_methods ,
10+ impl_clearable_for_chest , impl_inventory_for_chest , impl_viewer_count_listener_for_chest ,
2611 item:: ItemStack ,
27- world:: SimpleWorld ,
2812} ;
2913
30- use super :: BlockEntity ;
31-
3214pub struct ChestBlockEntity {
3315 pub position : BlockPos ,
3416 pub items : [ Arc < Mutex < ItemStack > > ; Self :: INVENTORY_SIZE ] ,
@@ -38,222 +20,16 @@ pub struct ChestBlockEntity {
3820 viewers : ViewerCountTracker ,
3921}
4022
41- impl BlockEntity for ChestBlockEntity {
42- fn resource_location ( & self ) -> & ' static str {
43- Self :: ID
44- }
45-
46- fn get_position ( & self ) -> BlockPos {
47- self . position
48- }
49-
50- fn from_nbt ( nbt : & pumpkin_nbt:: compound:: NbtCompound , position : BlockPos ) -> Self
51- where
52- Self : Sized ,
53- {
54- let chest = Self {
55- position,
56- items : from_fn ( |_| Arc :: new ( Mutex :: new ( ItemStack :: EMPTY . clone ( ) ) ) ) ,
57- dirty : AtomicBool :: new ( false ) ,
58- viewers : ViewerCountTracker :: new ( ) ,
59- } ;
60-
61- chest. read_data ( nbt, & chest. items ) ;
62-
63- chest
64- }
65-
66- fn write_nbt < ' a > (
67- & ' a self ,
68- nbt : & ' a mut NbtCompound ,
69- ) -> Pin < Box < dyn Future < Output = ( ) > + Send + ' a > > {
70- Box :: pin ( async move {
71- self . write_data ( nbt, & self . items , true ) . await ;
72- } )
73- // Safety precaution
74- //self.clear().await;
75- }
76-
77- fn tick < ' a > (
78- & ' a self ,
79- world : & ' a Arc < dyn SimpleWorld > ,
80- ) -> Pin < Box < dyn Future < Output = ( ) > + Send + ' a > > {
81- Box :: pin ( async move {
82- self . viewers
83- . update_viewer_count :: < Self > ( self , world, & self . position )
84- . await ;
85- } )
86- }
87-
88- fn get_inventory ( self : Arc < Self > ) -> Option < Arc < dyn Inventory > > {
89- Some ( self )
90- }
91-
92- fn is_dirty ( & self ) -> bool {
93- self . dirty . load ( Ordering :: Relaxed )
94- }
95-
96- fn as_any ( & self ) -> & dyn Any {
97- self
98- }
99- }
100-
101- impl ViewerCountListener for ChestBlockEntity {
102- fn on_container_open < ' a > (
103- & ' a self ,
104- world : & ' a Arc < dyn SimpleWorld > ,
105- _position : & ' a BlockPos ,
106- ) -> ViewerFuture < ' a , ( ) > {
107- Box :: pin ( async move {
108- self . play_sound ( world, Sound :: BlockChestOpen ) . await ;
109- } )
110- }
111-
112- fn on_container_close < ' a > (
113- & ' a self ,
114- world : & ' a Arc < dyn SimpleWorld > ,
115- _position : & ' a BlockPos ,
116- ) -> ViewerFuture < ' a , ( ) > {
117- Box :: pin ( async move {
118- self . play_sound ( world, Sound :: BlockChestClose ) . await ;
119- } )
120- }
121-
122- fn on_viewer_count_update < ' a > (
123- & ' a self ,
124- world : & ' a Arc < dyn SimpleWorld > ,
125- position : & ' a BlockPos ,
126- _old : u16 ,
127- new : u16 ,
128- ) -> ViewerFuture < ' a , ( ) > {
129- Box :: pin ( async move {
130- world
131- . add_synced_block_event ( * position, Self :: LID_ANIMATION_EVENT_TYPE , new as u8 )
132- . await ;
133- } )
134- }
135- }
13623impl ChestBlockEntity {
13724 pub const INVENTORY_SIZE : usize = 27 ;
13825 pub const LID_ANIMATION_EVENT_TYPE : u8 = 1 ;
13926 pub const ID : & ' static str = "minecraft:chest" ;
140-
141- /// Returns the number of players currently viewing this chest
142- pub fn get_viewer_count ( & self ) -> u16 {
143- self . viewers . get_viewer_count ( )
144- }
145-
146- #[ must_use]
147- pub fn new ( position : BlockPos ) -> Self {
148- Self {
149- position,
150- items : from_fn ( |_| Arc :: new ( Mutex :: new ( ItemStack :: EMPTY . clone ( ) ) ) ) ,
151- dirty : AtomicBool :: new ( false ) ,
152- viewers : ViewerCountTracker :: new ( ) ,
153- }
154- }
155-
156- async fn play_sound ( & self , world : & Arc < dyn SimpleWorld > , sound : Sound ) {
157- let mut rng = Xoroshiro :: from_seed ( get_seed ( ) ) ;
158-
159- let state = world. get_block_state ( & self . position ) . await ;
160- let properties = ChestLikeProperties :: from_state_id ( state. id , & Block :: CHEST ) ;
161- let position = match properties. r#type {
162- ChestType :: Left => return ,
163- ChestType :: Single => Vector3 :: new (
164- self . position . 0 . x as f64 + 0.5 ,
165- self . position . 0 . y as f64 + 0.5 ,
166- self . position . 0 . z as f64 + 0.5 ,
167- ) ,
168- ChestType :: Right => {
169- let direction = properties. facing . to_block_direction ( ) . to_offset ( ) ;
170- Vector3 :: new (
171- self . position . 0 . x as f64 + 0.5 + direction. x as f64 * 0.5 ,
172- self . position . 0 . y as f64 + 0.5 ,
173- self . position . 0 . z as f64 + 0.5 + direction. z as f64 * 0.5 ,
174- )
175- }
176- } ;
177-
178- world
179- . play_sound_fine (
180- sound,
181- SoundCategory :: Blocks ,
182- & position,
183- 0.5 ,
184- rng. next_f32 ( ) * 0.1 + 0.9 ,
185- )
186- . await ;
187- }
188- }
189-
190- impl Inventory for ChestBlockEntity {
191- fn size ( & self ) -> usize {
192- self . items . len ( )
193- }
194-
195- fn is_empty ( & self ) -> InventoryFuture < ' _ , bool > {
196- Box :: pin ( async move {
197- for slot in & self . items {
198- if !slot. lock ( ) . await . is_empty ( ) {
199- return false ;
200- }
201- }
202-
203- true
204- } )
205- }
206-
207- fn get_stack ( & self , slot : usize ) -> InventoryFuture < ' _ , Arc < Mutex < ItemStack > > > {
208- Box :: pin ( async move { self . items [ slot] . clone ( ) } )
209- }
210-
211- fn remove_stack ( & self , slot : usize ) -> InventoryFuture < ' _ , ItemStack > {
212- Box :: pin ( async move {
213- let mut removed = ItemStack :: EMPTY . clone ( ) ;
214- let mut guard = self . items [ slot] . lock ( ) . await ;
215- std:: mem:: swap ( & mut removed, & mut * guard) ;
216- removed
217- } )
218- }
219-
220- fn remove_stack_specific ( & self , slot : usize , amount : u8 ) -> InventoryFuture < ' _ , ItemStack > {
221- Box :: pin ( async move { split_stack ( & self . items , slot, amount) . await } )
222- }
223-
224- fn set_stack ( & self , slot : usize , stack : ItemStack ) -> InventoryFuture < ' _ , ( ) > {
225- Box :: pin ( async move {
226- * self . items [ slot] . lock ( ) . await = stack;
227- } )
228- }
229-
230- fn on_open ( & self ) -> InventoryFuture < ' _ , ( ) > {
231- Box :: pin ( async move {
232- self . viewers . open_container ( ) ;
233- } )
234- }
235-
236- fn on_close ( & self ) -> InventoryFuture < ' _ , ( ) > {
237- Box :: pin ( async move {
238- self . viewers . close_container ( ) ;
239- } )
240- }
241-
242- fn mark_dirty ( & self ) {
243- self . dirty . store ( true , Ordering :: Relaxed ) ;
244- }
245-
246- fn as_any ( & self ) -> & dyn Any {
247- self
248- }
27+ pub const EMITS_REDSTONE : bool = false ;
24928}
25029
251- impl Clearable for ChestBlockEntity {
252- fn clear ( & self ) -> Pin < Box < dyn Future < Output = ( ) > + Send + ' _ > > {
253- Box :: pin ( async move {
254- for slot in & self . items {
255- * slot. lock ( ) . await = ItemStack :: EMPTY . clone ( ) ;
256- }
257- } )
258- }
259- }
30+ // Apply macros to generate trait implementations
31+ impl_block_entity_for_chest ! ( ChestBlockEntity ) ;
32+ impl_inventory_for_chest ! ( ChestBlockEntity ) ;
33+ impl_clearable_for_chest ! ( ChestBlockEntity ) ;
34+ impl_viewer_count_listener_for_chest ! ( ChestBlockEntity ) ;
35+ impl_chest_helper_methods ! ( ChestBlockEntity ) ;
0 commit comments