2323import net .minecraft .world .level .block .state .BlockState ;
2424import net .minecraft .world .level .block .state .StateDefinition ;
2525import net .minecraft .world .level .block .state .properties .*;
26+ import net .minecraft .world .level .gameevent .GameEvent ;
2627import net .minecraft .world .phys .BlockHitResult ;
2728import net .minecraft .world .phys .shapes .Shapes ;
2829import net .minecraft .world .phys .shapes .VoxelShape ;
3334
3435import java .util .function .Supplier ;
3536
37+ // DoorBlock
38+
3639public abstract class AbstractWorkbench <E extends AbstractWorkbenchEntity > extends BaseEntityBlock {
3740 public static final EnumProperty <Direction > FACING = HorizontalDirectionalBlock .FACING ;
3841 public static final EnumProperty <DoubleBlockHalf > HALF = BlockStateProperties .DOUBLE_BLOCK_HALF ;
@@ -351,4 +354,52 @@ protected float getShadeBrightness(BlockState state, BlockGetter level, BlockPos
351354 // We want 1.0F to ensure the block doesn't cast a pitch-black shadow on itself.
352355 return 1.0F ;
353356 }
357+
358+ @ Override
359+ public BlockState playerWillDestroy (Level level , BlockPos pos , BlockState state , Player player ) {
360+ if (!level .isClientSide ()) {
361+ BlockPos masterPos = getMasterPos (state , pos );
362+ boolean isMaster = pos .equals (masterPos );
363+
364+ // Iterate through the entire 2x2 or 1x2 structure
365+ for (int y = 0 ; y <= (isTall ? 1 : 0 ); y ++) {
366+ for (int x = 0 ; x <= (isWide ? 1 : 0 ); x ++) {
367+ Direction facing = state .getValue (FACING );
368+ BlockPos targetPos = masterPos .above (y ).relative (facing .getClockWise (), x );
369+
370+ // Skip the block the player is currently mining
371+ if (targetPos .equals (pos )) continue ;
372+
373+ BlockState targetState = level .getBlockState (targetPos );
374+ if (targetState .is (this ) && getMasterPos (targetState , targetPos ).equals (masterPos )) {
375+ if (isMaster ) {
376+ // If we are mining the Master, destroy others SILENTLY
377+ level .setBlock (targetPos , Blocks .AIR .defaultBlockState (), 35 );
378+ } else {
379+ // If we are mining a Slave block, we need to handle the Master carefully.
380+ // If the Master is at this targetPos, destroy it WITH drops.
381+ if (targetPos .equals (masterPos )) {
382+ level .destroyBlock (targetPos , !player .isCreative ());
383+ } else {
384+ // Otherwise, it's just another slave block, remove silently.
385+ level .setBlock (targetPos , Blocks .AIR .defaultBlockState (), 35 );
386+ }
387+ }
388+ level .gameEvent (GameEvent .BLOCK_DESTROY , targetPos , GameEvent .Context .of (player , targetState ));
389+ }
390+ }
391+ }
392+
393+ // Final tweak: If the player is mining a SLAVE block,
394+ // we must prevent the slave block itself from dropping.
395+ if (!isMaster && !player .isCreative ()) {
396+ // This prevents the current block from dropping its loot table
397+ // because we already triggered the Master's drop above.
398+ state = state .setValue (BlockStateProperties .LIT , false ); // Optional: change state to desync loot
399+ level .setBlock (pos , Blocks .AIR .defaultBlockState (), 35 );
400+ }
401+ }
402+
403+ return super .playerWillDestroy (level , pos , state , player );
404+ }
354405}
0 commit comments