11package com .tcm .MineTale .block ;
22
33import com .mojang .serialization .MapCodec ;
4+ import com .tcm .MineTale .block .entity .ChickenCoopEntity ;
5+ import com .tcm .MineTale .registry .ModBlockEntities ;
46import com .tcm .MineTale .util .CoopPart ;
57
68import net .minecraft .core .BlockPos ;
79import net .minecraft .core .Direction ;
10+ import net .minecraft .sounds .SoundEvents ;
11+ import net .minecraft .sounds .SoundSource ;
812import net .minecraft .util .RandomSource ;
13+ import net .minecraft .world .InteractionResult ;
914import net .minecraft .world .entity .LivingEntity ;
1015import net .minecraft .world .entity .player .Player ;
1116import net .minecraft .world .item .ItemStack ;
17+ import net .minecraft .world .item .Items ;
1218import net .minecraft .world .item .context .BlockPlaceContext ;
1319import net .minecraft .world .level .Level ;
1420import net .minecraft .world .level .LevelReader ;
1521import net .minecraft .world .level .ScheduledTickAccess ;
1622import net .minecraft .world .level .block .Block ;
1723import net .minecraft .world .level .block .Blocks ;
24+ import net .minecraft .world .level .block .EntityBlock ;
1825import net .minecraft .world .level .block .HorizontalDirectionalBlock ;
1926import net .minecraft .world .level .block .entity .BlockEntity ;
27+ import net .minecraft .world .level .block .entity .BlockEntityTicker ;
28+ import net .minecraft .world .level .block .entity .BlockEntityType ;
2029import net .minecraft .world .level .block .state .BlockState ;
2130import net .minecraft .world .level .block .state .StateDefinition ;
2231import net .minecraft .world .level .block .state .properties .EnumProperty ;
32+ import net .minecraft .world .phys .BlockHitResult ;
33+
2334import org .jetbrains .annotations .Nullable ;
2435
25- public class ChickenCoopBlock extends HorizontalDirectionalBlock {
36+ public class ChickenCoopBlock extends HorizontalDirectionalBlock implements EntityBlock {
2637 public static final EnumProperty <CoopPart > PART = EnumProperty .create ("part" , CoopPart .class );
2738
2839 public static final MapCodec <ChickenCoopBlock > CODEC = simpleCodec (ChickenCoopBlock ::new );
2940
41+ /**
42+ * Create a ChickenCoopBlock configured with the provided block properties and a default state.
43+ *
44+ * The default state sets FACING to NORTH and PART to CoopPart.BOTTOM_FRONT_LEFT.
45+ *
46+ * @param properties block properties used to configure this block's behaviour and characteristics
47+ */
3048 public ChickenCoopBlock (Properties properties ) {
3149 super (properties );
3250 // Default to the origin part (Bottom Front Left) facing North
@@ -35,6 +53,57 @@ public ChickenCoopBlock(Properties properties) {
3553 .setValue (PART , CoopPart .BOTTOM_FRONT_LEFT ));
3654 }
3755
56+ /**
57+ * Provides a BlockEntityTicker for the coop's centre-front part on the server.
58+ *
59+ * Returns a ticker that delegates to ChickenCoopEntity.tick when the call is on the logical server,
60+ * the block state's PART is BOTTOM_FRONT_CENTER and the requested BlockEntityType equals ModBlockEntities.CHICKEN_COOP_BE.
61+ *
62+ * @param <T> the block entity type
63+ * @param level the level containing the block
64+ * @param state the block state for which a ticker is requested
65+ * @param type the requested block entity type
66+ * @return a ticker delegating to ChickenCoopEntity.tick when applicable, `null` otherwise
67+ */
68+ @ Nullable
69+ @ Override
70+ public <T extends BlockEntity > BlockEntityTicker <T > getTicker (Level level , BlockState state , BlockEntityType <T > type ) {
71+ // 1. Only tick on server side
72+ if (level .isClientSide ()) return null ;
73+
74+ // 2. Only tick if this is the correct part of the coop
75+ if (state .getValue (PART ) != CoopPart .BOTTOM_FRONT_CENTER ) return null ;
76+
77+ // 3. Link to the static tick method in your Entity class
78+ return type == ModBlockEntities .CHICKEN_COOP_BE
79+ ? (lvl , pos , st , be ) -> ChickenCoopEntity .tick (lvl , pos , st , (ChickenCoopEntity ) be )
80+ : null ;
81+ }
82+
83+ /**
84+ * Creates the block entity for the coop when this block represents the centre-front (brain) part.
85+ *
86+ * @param pos the block position
87+ * @param state the current block state
88+ * @return {@code ChickenCoopEntity} for the centre-front part, {@code null} otherwise
89+ */
90+ @ Nullable
91+ @ Override
92+ public BlockEntity newBlockEntity (BlockPos pos , BlockState state ) {
93+ // Only the center-front part gets the "brain"
94+ if (state .getValue (PART ) == CoopPart .BOTTOM_FRONT_CENTER ) {
95+ return new ChickenCoopEntity (pos , state );
96+ }
97+ return null ;
98+ }
99+
100+ /**
101+ * Registers this block's state properties.
102+ *
103+ * Adds the horizontal facing and coop part properties so block states can represent orientation and segment.
104+ *
105+ * @param builder the state definition builder to register properties with
106+ */
38107 @ Override
39108 protected void createBlockStateDefinition (StateDefinition .Builder <Block , BlockState > builder ) {
40109 builder .add (FACING , PART );
@@ -185,7 +254,14 @@ public BlockState playerWillDestroy(Level level, BlockPos pos, BlockState state,
185254 }
186255
187256 /**
188- * Rotates the 3x3x2 grid logic based on which way the player is facing.
257+ * Compute the world block position for a local coordinate inside the coop's 3×2×3 grid, taking block facing into account.
258+ *
259+ * @param origin the reference origin position (the block considered as the grid origin)
260+ * @param facing the horizontal direction the coop is facing; used to convert local depth into world direction
261+ * @param x local x index in the 3-wide grid (0 = left, 1 = centre, 2 = right)
262+ * @param z local depth index along the facing direction (0..2); larger values are further away from the player
263+ * @param y local vertical index (0..2) measured as blocks above the origin
264+ * @return the computed BlockPos in world coordinates for the given local grid coordinate
189265 */
190266 private BlockPos calculateOffset (BlockPos origin , Direction facing , int x , int z , int y ) {
191267 // x-1 centers the 3-wide structure (0=left, 1=center, 2=right)
@@ -198,8 +274,67 @@ private BlockPos calculateOffset(BlockPos origin, Direction facing, int x, int z
198274 .above (y );
199275 }
200276
201- @ Override
277+ /**
278+ * Provide the block's MapCodec used by the game's codec system for (de)serialisation.
279+ *
280+ * @return the MapCodec instance for this block's state
281+ */
282+ @ Override
202283 protected MapCodec <? extends HorizontalDirectionalBlock > codec () {
203284 return CODEC ;
204285 }
205- }
286+
287+ /**
288+ * Handle interaction with the coop when used without an item, dispensing any collected eggs to the player.
289+ *
290+ * On the client this returns `InteractionResult.SUCCESS`. On the server this locates the coop's brain
291+ * block entity (the bottom-front-center part); if that entity has eggs they are transferred to the player
292+ * (or dropped at the player's feet if their inventory is full) and a chicken-egg sound is played.
293+ *
294+ * @param state the current block state
295+ * @param level the level where the block is located
296+ * @param pos the position of the interacted block
297+ * @param player the player performing the interaction
298+ * @param hitResult hit information for the interaction
299+ * @return `InteractionResult.SUCCESS` if eggs were given or on the client, `InteractionResult.PASS` otherwise.
300+ */
301+ @ Override
302+ protected InteractionResult useWithoutItem (BlockState state , Level level , BlockPos pos , Player player , BlockHitResult hitResult ) {
303+ if (level .isClientSide ()) return InteractionResult .SUCCESS ;
304+
305+ // 1. Find the "brain" position (the Bottom Front Center)
306+ Direction facing = state .getValue (FACING );
307+ CoopPart currentPart = state .getValue (PART );
308+
309+ // Calculate the origin (Bottom Front Center is our origin in calculateOffset logic)
310+ // Based on your calculateOffset, the BFC is at x=1, z=0, y=0.
311+ BlockPos brainPos = pos .subtract (calculateOffset (BlockPos .ZERO , facing ,
312+ currentPart .getXOffset (), currentPart .getZOffset (), currentPart .getYOffset ()))
313+ .relative (facing , 0 ) // already at z=0
314+ .relative (facing .getClockWise (), 0 ); // x=1 is center, so we shift back to it
315+
316+ // Easier way: Since you know the brain is always at BOTTOM_FRONT_CENTER:
317+ // We just need to find where that specific part is relative to the current block.
318+ // However, your 'calculateOffset' is already the source of truth.
319+
320+ if (level .getBlockEntity (brainPos ) instanceof ChickenCoopEntity coopBe ) {
321+ int eggsToGive = coopBe .takeAllEggs ();
322+
323+ if (eggsToGive > 0 ) {
324+ // Give the player an egg
325+ ItemStack eggStack = new ItemStack (Items .EGG , eggsToGive );
326+ if (!player .getInventory ().add (eggStack )) {
327+ // If inventory full, drop at player's feet
328+ player .drop (eggStack , false );
329+ }
330+
331+ // Play a sound to give feedback
332+ level .playSound (null , pos , SoundEvents .CHICKEN_EGG , SoundSource .PLAYERS , 1.0f , 1.0f );
333+ return InteractionResult .SUCCESS ;
334+ }
335+ }
336+
337+ return InteractionResult .PASS ;
338+ }
339+
340+ }
0 commit comments