2121import meteordevelopment .orbit .EventHandler ;
2222import meteordevelopment .orbit .EventPriority ;
2323import net .minecraft .core .BlockPos ;
24+ import net .minecraft .core .Direction ;
2425import net .minecraft .network .protocol .game .ServerboundMovePlayerPacket ;
2526import net .minecraft .tags .BlockTags ;
2627import net .minecraft .world .item .Item ;
2728import net .minecraft .world .level .block .Blocks ;
2829import net .minecraft .world .level .block .CropBlock ;
2930import net .minecraft .world .level .block .NetherWartBlock ;
3031import net .minecraft .world .level .block .state .BlockState ;
32+ import net .minecraft .world .level .block .state .properties .BlockStateProperties ;
3133
3234import java .util .ArrayList ;
3335
@@ -60,7 +62,14 @@ public class BetterFarming extends Module {
6062
6163 private final Setting <Boolean > noBreakCaneBase = sgNoBreak .add (new BoolSetting .Builder ()
6264 .name ("no-break-cane-base" )
63- .description ("Prevents player from breaking the base of sugarcane and bamboo blocks." )
65+ .description ("Prevents player from breaking the base of sugarcane, bamboo and cactus blocks." )
66+ .defaultValue (true )
67+ .build ()
68+ );
69+
70+ private final Setting <Boolean > noBreakSupportingBlocks = sgNoBreak .add (new BoolSetting .Builder ()
71+ .name ("no-break-supporting-blocks" )
72+ .description ("Prevents player from breaking the block supporting a crop, eg. Jungle log with cocoa, budding amethyst, sand under cactus." )
6473 .defaultValue (true )
6574 .build ()
6675 );
@@ -81,7 +90,8 @@ private void onTick(TickEvent.Pre event) {
8190 @ EventHandler (priority = EventPriority .HIGH )
8291 private void onStartBreakingBlockEvent (StartBreakingBlockEvent event ) {
8392 if (noBreakUnripe .get ()) noBreakUnripeBreakEvent (event );
84- if (noBreakCaneBase .get ()) noBreakCaneBaseEvent (event );
93+ if (noBreakCaneBase .get ()) noBreakCaneBaseBreakEvent (event );
94+ if (noBreakSupportingBlocks .get ()) noBreakSupportingBlocksBreakEvent (event );
8595 if (cropReplace .get ()) autoPlaceBreakEvent (event );
8696 }
8797
@@ -106,18 +116,81 @@ private void noBreakUnripeBreakEvent(StartBreakingBlockEvent event) {
106116 }
107117 }
108118
109- private void noBreakCaneBaseEvent (StartBreakingBlockEvent event ) {
119+ private boolean isCaneBlock (BlockState blockState ) {
120+ return blockState .is (Blocks .SUGAR_CANE )
121+ || blockState .is (Blocks .BAMBOO )
122+ || blockState .is (Blocks .CACTUS );
123+ }
124+
125+ private boolean isSupportedBelowCrop (BlockState blockState ) {
126+ return blockState .is (BlockTags .CROPS )
127+ || blockState .is (Blocks .NETHER_WART )
128+ || isCaneBlock (blockState );
129+ }
130+
131+ private boolean isReplaceableCrop (BlockState blockState ) {
132+ return blockState .is (BlockTags .CROPS )
133+ || blockState .is (Blocks .NETHER_WART );
134+ }
135+
136+ private boolean checkForCocoa (BlockPos blockPos ) {
137+ Direction [] checkDirections = {
138+ Direction .NORTH ,
139+ Direction .SOUTH ,
140+ Direction .EAST ,
141+ Direction .WEST ,
142+ };
143+
144+ for (Direction direction : checkDirections ) {
145+ // Check block at blockPos offset by the direction normal vector.
146+ BlockState bsCheck = mc .level .getBlockState (blockPos .offset (direction .getUnitVec3i ()));
147+
148+ if (bsCheck .is (Blocks .COCOA )) {
149+
150+ Direction facingDirection = bsCheck .getValue (BlockStateProperties .HORIZONTAL_FACING );
151+
152+ if (facingDirection == direction .getOpposite ()) {
153+ return true ;
154+ }
155+ }
156+
157+ }
158+
159+ return false ;
160+ }
161+
162+ private void noBreakCaneBaseBreakEvent (StartBreakingBlockEvent event ) {
110163 BlockState blockState = mc .level .getBlockState (event .blockPos );
111164 BlockState bsBelow = mc .level .getBlockState (event .blockPos .offset (0 , -1 , 0 ));
112165
113- boolean bsIsCane = (blockState . is ( Blocks . SUGAR_CANE ) || blockState . is ( Blocks . BAMBOO ) );
114- boolean bsBelowIsCane = (bsBelow . is ( Blocks . SUGAR_CANE ) || bsBelow . is ( Blocks . BAMBOO ) );
166+ boolean bsIsCane = isCaneBlock (blockState );
167+ boolean bsBelowIsCane = isCaneBlock (bsBelow );
115168
116169 if (!bsIsCane || bsBelowIsCane ) return ;
117170
118171 event .cancel ();
119172 }
120173
174+ private void noBreakSupportingBlocksBreakEvent (StartBreakingBlockEvent event ) {
175+ BlockPos blockPos = event .blockPos ;
176+ BlockState blockState = mc .level .getBlockState (blockPos );
177+ BlockState bsAbove = mc .level .getBlockState (blockPos .offset (0 , 1 , 0 ));
178+
179+ if (!isSupportedBelowCrop (blockState ) && isSupportedBelowCrop (bsAbove )) {
180+ event .cancel ();
181+ return ;
182+ }
183+
184+ if (blockState .is (BlockTags .SUPPORTS_COCOA ) && checkForCocoa (blockPos )) {
185+ event .cancel ();
186+ return ;
187+ }
188+
189+ if (blockState .is (Blocks .BUDDING_AMETHYST )) {
190+ event .cancel ();
191+ }
192+ }
193+
121194 private void autoPlaceTick () {
122195 if (blockBreakCooldown > 0 ) {
123196 blockBreakCooldown --;
@@ -151,7 +224,7 @@ private void autoPlaceBreakEvent(StartBreakingBlockEvent event) {
151224
152225 BlockState blockState = mc .level .getBlockState (event .blockPos );
153226
154- if (!(blockState . is ( BlockTags . CROPS ) || blockState . is ( Blocks . NETHER_WART ) )) return ;
227+ if (!isReplaceableCrop (blockState )) return ;
155228
156229 if (blockBreakCooldown > 0 ) {
157230 event .cancel ();
0 commit comments