-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Better Farming module (crop farming improvements) #6417
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
moxvallix
wants to merge
6
commits into
MeteorDevelopment:master
Choose a base branch
from
optipack:better-farming
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+291
−0
Open
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
81da32b
feat(module): implement initial version of better farming
moxvallix bc45504
feat(module): add no break unripe to better farming
moxvallix 7abf97e
feat(module): add no break for cane blocks, also unripe nether wart
moxvallix 935a8a0
feat(module): implement no break supporting blocks in to better farming
moxvallix 6607dc6
chore: implement recommended changes
moxvallix 8d3c3fe
chore: implement one more recommended change
moxvallix File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
290 changes: 290 additions & 0 deletions
290
src/main/java/meteordevelopment/meteorclient/systems/modules/player/BetterFarming.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,290 @@ | ||
| /* | ||
| * This file is part of the Meteor Client distribution (https://github.com/MeteorDevelopment/meteor-client). | ||
| * Copyright (c) Meteor Development. | ||
| */ | ||
|
|
||
| package meteordevelopment.meteorclient.systems.modules.player; | ||
|
|
||
| import meteordevelopment.meteorclient.events.entity.player.StartBreakingBlockEvent; | ||
| import meteordevelopment.meteorclient.events.packets.PacketEvent; | ||
| import meteordevelopment.meteorclient.events.world.TickEvent; | ||
| import meteordevelopment.meteorclient.mixin.ServerboundMovePlayerPacketAccessor; | ||
| import meteordevelopment.meteorclient.mixininterface.IServerboundMovePlayerPacket; | ||
| import meteordevelopment.meteorclient.settings.BoolSetting; | ||
| import meteordevelopment.meteorclient.settings.Setting; | ||
| import meteordevelopment.meteorclient.settings.SettingGroup; | ||
| import meteordevelopment.meteorclient.systems.modules.Categories; | ||
| import meteordevelopment.meteorclient.systems.modules.Module; | ||
| import meteordevelopment.meteorclient.utils.player.FindItemResult; | ||
| import meteordevelopment.meteorclient.utils.player.InvUtils; | ||
| import meteordevelopment.meteorclient.utils.world.BlockUtils; | ||
| import meteordevelopment.orbit.EventHandler; | ||
| import meteordevelopment.orbit.EventPriority; | ||
| import net.minecraft.core.BlockPos; | ||
| import net.minecraft.core.Direction; | ||
| import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; | ||
| import net.minecraft.tags.BlockTags; | ||
| import net.minecraft.util.ArrayListDeque; | ||
| import net.minecraft.world.item.Item; | ||
| import net.minecraft.world.level.block.Blocks; | ||
| import net.minecraft.world.level.block.CropBlock; | ||
| import net.minecraft.world.level.block.NetherWartBlock; | ||
| import net.minecraft.world.level.block.state.BlockState; | ||
| import net.minecraft.world.level.block.state.properties.BlockStateProperties; | ||
|
|
||
| import java.util.ArrayList; | ||
|
|
||
| public class BetterFarming extends Module { | ||
| private final SettingGroup sgGeneral = settings.getDefaultGroup(); | ||
| private final SettingGroup sgNoBreak = settings.createGroup("No Break"); | ||
|
|
||
| // General | ||
|
|
||
| private final Setting<Boolean> cropReplace = sgGeneral.add(new BoolSetting.Builder() | ||
| .name("crop-replace") | ||
| .description("Automatically plant new crop on harvest.") | ||
| .defaultValue(true) | ||
| .build() | ||
| ); | ||
|
|
||
| private final Setting<Boolean> suppressTrample = sgGeneral.add(new BoolSetting.Builder() | ||
| .name("suppress-trample") | ||
| .description("Attempts to prevent player from trampling crops.") | ||
| .defaultValue(true) | ||
| .build() | ||
| ); | ||
|
|
||
| private final Setting<Boolean> noBreakUnripe = sgNoBreak.add(new BoolSetting.Builder() | ||
| .name("no-break-unripe") | ||
| .description("Prevents player from breaking unripe crops.") | ||
| .defaultValue(true) | ||
| .build() | ||
| ); | ||
|
|
||
| private final Setting<Boolean> noBreakCaneBase = sgNoBreak.add(new BoolSetting.Builder() | ||
| .name("no-break-cane-base") | ||
| .description("Prevents player from breaking the base of sugarcane, bamboo and cactus blocks.") | ||
| .defaultValue(true) | ||
| .build() | ||
| ); | ||
|
|
||
| private final Setting<Boolean> noBreakSupportingBlocks = sgNoBreak.add(new BoolSetting.Builder() | ||
| .name("no-break-supporting-blocks") | ||
| .description("Prevents player from breaking the block supporting a crop, eg. Jungle log with cocoa, budding amethyst, sand under cactus.") | ||
| .defaultValue(true) | ||
| .build() | ||
| ); | ||
|
|
||
| public BetterFarming() { | ||
| super(Categories.Player, "better-farming", "Improvements for crop farming."); | ||
| } | ||
|
|
||
| private Item placeItem = null; | ||
| private final ArrayListDeque<BlockPos> cropPlacements = new ArrayListDeque<>(); | ||
| private int blockBreakCooldown = 0; | ||
|
|
||
| @EventHandler(priority = EventPriority.HIGH) | ||
| private void onTick(TickEvent.Pre event) { | ||
| if (cropReplace.get()) autoPlaceTick(); | ||
| } | ||
|
|
||
| @EventHandler(priority = EventPriority.HIGH) | ||
| private void onStartBreakingBlockEvent(StartBreakingBlockEvent event) { | ||
| if (noBreakUnripe.get()) noBreakUnripeBreakEvent(event); | ||
| if (noBreakCaneBase.get()) noBreakCaneBaseBreakEvent(event); | ||
| if (noBreakSupportingBlocks.get()) noBreakSupportingBlocksBreakEvent(event); | ||
| if (cropReplace.get()) autoPlaceBreakEvent(event); | ||
| } | ||
|
|
||
| @EventHandler | ||
| private void onSendPacket(PacketEvent.Send event) { | ||
| if (suppressTrample.get()) trampleSuppressionSendEvent(event); | ||
| } | ||
|
|
||
| private void noBreakUnripeBreakEvent(StartBreakingBlockEvent event) { | ||
| BlockState blockState = mc.level.getBlockState(event.blockPos); | ||
|
|
||
| if (blockState.getBlock() instanceof CropBlock cropBlock) { | ||
| if (cropBlock.isMaxAge(blockState)) return; | ||
|
|
||
| event.cancel(); | ||
| } | ||
|
|
||
| if (blockState.getBlock() instanceof NetherWartBlock) { | ||
| if (blockState.getValue(NetherWartBlock.AGE) >= NetherWartBlock.MAX_AGE) return; | ||
|
|
||
| event.cancel(); | ||
| } | ||
| } | ||
|
|
||
| private boolean isCaneBlock(BlockState blockState) { | ||
| return blockState.is(Blocks.SUGAR_CANE) | ||
| || blockState.is(Blocks.BAMBOO) | ||
| || blockState.is(Blocks.CACTUS); | ||
| } | ||
|
|
||
| private boolean isSupportedBelowCrop(BlockState blockState) { | ||
| return blockState.is(BlockTags.CROPS) | ||
| || blockState.is(Blocks.NETHER_WART) | ||
| || isCaneBlock(blockState); | ||
| } | ||
|
|
||
| private boolean isReplaceableCrop(BlockState blockState) { | ||
| return blockState.is(BlockTags.CROPS) | ||
| || blockState.is(Blocks.NETHER_WART); | ||
| } | ||
|
|
||
| private boolean checkForCocoa(BlockPos blockPos) { | ||
| Direction[] checkDirections = { | ||
| Direction.NORTH, | ||
| Direction.SOUTH, | ||
| Direction.EAST, | ||
| Direction.WEST, | ||
| }; | ||
|
|
||
| for (Direction direction : checkDirections) { | ||
| // Check block at blockPos offset by the direction normal vector. | ||
| BlockState bsCheck = mc.level.getBlockState(blockPos.relative(direction)); | ||
|
|
||
| if (bsCheck.is(Blocks.COCOA)) { | ||
|
|
||
| Direction facingDirection = bsCheck.getValue(BlockStateProperties.HORIZONTAL_FACING); | ||
|
|
||
| if (facingDirection == direction.getOpposite()) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| } | ||
|
|
||
| return false; | ||
| } | ||
|
|
||
| private void noBreakCaneBaseBreakEvent(StartBreakingBlockEvent event) { | ||
| BlockState blockState = mc.level.getBlockState(event.blockPos); | ||
| BlockState bsBelow = mc.level.getBlockState(event.blockPos.offset(0, -1, 0)); | ||
|
|
||
| boolean bsIsCane = isCaneBlock(blockState); | ||
| boolean bsBelowIsCane = isCaneBlock(bsBelow); | ||
|
|
||
| if (!bsIsCane || bsBelowIsCane) return; | ||
|
|
||
| event.cancel(); | ||
| } | ||
|
|
||
| private void noBreakSupportingBlocksBreakEvent(StartBreakingBlockEvent event) { | ||
| BlockPos blockPos = event.blockPos; | ||
| BlockState blockState = mc.level.getBlockState(blockPos); | ||
| BlockState bsAbove = mc.level.getBlockState(blockPos.above()); | ||
|
|
||
| if (!isSupportedBelowCrop(blockState) && isSupportedBelowCrop(bsAbove)) { | ||
| event.cancel(); | ||
| return; | ||
| } | ||
|
|
||
| if (blockState.is(BlockTags.SUPPORTS_COCOA) && checkForCocoa(blockPos)) { | ||
| event.cancel(); | ||
| return; | ||
| } | ||
|
|
||
| if (blockState.is(Blocks.BUDDING_AMETHYST)) { | ||
| event.cancel(); | ||
| } | ||
| } | ||
|
|
||
| private void autoPlaceTick() { | ||
| if (blockBreakCooldown > 0) { | ||
| blockBreakCooldown--; | ||
| } | ||
|
|
||
| if (placeItem == null) return; | ||
| if (cropPlacements.isEmpty()) { | ||
| placeItem = null; | ||
| return; | ||
| } | ||
|
|
||
| BlockPos blockPos = cropPlacements.getFirst(); | ||
| cropPlacements.removeFirst(); | ||
|
|
||
| FindItemResult foundItem = InvUtils.find(placeItem); | ||
|
|
||
| // If the found item is not in mainhand yet, its not ready | ||
| if (!foundItem.isMainHand()) return; | ||
|
|
||
| BlockState blockState = mc.level.getBlockState(blockPos); | ||
|
|
||
| if (blockState.is(BlockTags.AIR)) { | ||
| BlockUtils.place(blockPos, foundItem, 0); | ||
| } else { | ||
| BlockUtils.breakBlock(blockPos, true); | ||
| } | ||
| } | ||
|
|
||
| private void autoPlaceBreakEvent(StartBreakingBlockEvent event) { | ||
| if (event.isCancelled()) return; | ||
|
|
||
| BlockState blockState = mc.level.getBlockState(event.blockPos); | ||
|
|
||
| if (!isReplaceableCrop(blockState)) return; | ||
|
|
||
| if (blockBreakCooldown > 0) { | ||
| event.cancel(); | ||
| return; | ||
| } | ||
|
|
||
| Item blockItem = blockState.getBlock().asItem(); | ||
| FindItemResult foundItem = InvUtils.find(blockItem); | ||
|
|
||
| if (!foundItem.found()) return; | ||
|
|
||
| placeItem = blockItem; | ||
| cropPlacements.add(event.blockPos); | ||
|
|
||
| if (foundItem.isMainHand()) { | ||
| blockBreakCooldown = 3; | ||
| return; | ||
| } | ||
|
|
||
| mc.gameMode.handlePickItemFromBlock(event.blockPos, false); | ||
|
|
||
| // Cancel the event to allow pickblock to do its thing | ||
| event.cancel(); | ||
| } | ||
|
|
||
| private void trampleSuppressionSendEvent(PacketEvent.Send event) { | ||
| if (mc.player == null) return; | ||
| if (!(event.packet instanceof ServerboundMovePlayerPacket) | ||
|
moxvallix marked this conversation as resolved.
|
||
| || ((IServerboundMovePlayerPacket) event.packet).meteor$getTag() == 1337) return; | ||
|
|
||
| ServerboundMovePlayerPacket packet = (ServerboundMovePlayerPacket) event.packet; | ||
|
|
||
| BlockPos blockPos = BlockPos.containing( | ||
| packet.getX(0d), | ||
| packet.getY(0d), | ||
| packet.getZ(0d) | ||
| ); | ||
|
|
||
| // Only suppress fall if blocks beneath are farmland | ||
| // Check 3x3 area beneath player, for if the player jumps on the edge | ||
| BlockPos[] posChecks = { | ||
| blockPos.offset(-1, -1, -1), | ||
| blockPos.offset(-1, -1, 0), | ||
| blockPos.offset(-1, -1, 1), | ||
| blockPos.offset(0, -1, -1), | ||
| blockPos.offset(0, -1, 0), | ||
| blockPos.offset(0, -1, 1), | ||
| blockPos.offset(1, -1, -1), | ||
| blockPos.offset(1, -1, 0), | ||
| blockPos.offset(1, -1, 1), | ||
| }; | ||
|
|
||
| for (BlockPos pos : posChecks) { | ||
| BlockState blockState = mc.level.getBlockState(pos); | ||
|
|
||
| if (blockState.is(Blocks.FARMLAND)) { | ||
| ((ServerboundMovePlayerPacketAccessor) event.packet).meteor$setOnGround(true); | ||
| break; | ||
| } | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.