Skip to content
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

Add AutoPlaceHack #1051

Open
wants to merge 26 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
1ebb8d9
Add AutoPlaceHack
LilyKensa Aug 8, 2024
76a5b03
Merge branch 'master' into master
LilyKensa Aug 8, 2024
d4b624e
Merge pull request #1 from Wurst-Imperium/master
LilyKensa Aug 9, 2024
21ce72b
Add TeamEspHack & FilterNpcLikeSetting
LilyKensa Aug 9, 2024
32f85be
Merge pull request #2 from Wurst-Imperium/master
LilyKensa Aug 9, 2024
0998d1d
Merge pull request #3 from LilyKensa/teamesp-pr
LilyKensa Aug 9, 2024
e27ce53
Add FilterTeammatesSetting
LilyKensa Aug 10, 2024
0b0ec5f
Merge pull request #4 from LilyKensa/teamesp-pr
LilyKensa Aug 10, 2024
90e45c0
Add AimAssistHack onlyHoldingWeapon option
LilyKensa Aug 25, 2024
f3584a6
Merge pull request #5 from LilyKensa/onlyholdingweapon-pr
LilyKensa Aug 25, 2024
74c4def
Add TriggerBotHack blacklistedItems option
LilyKensa Aug 25, 2024
5559d0f
Merge pull request #6 from LilyKensa/triggerbotitemblacklist-pr
LilyKensa Aug 25, 2024
a1e7c2e
Add SafeWalkHack minDepth & motionPrediction options
LilyKensa Aug 25, 2024
bb0215f
Merge pull request #7 from LilyKensa/safewalkmindepth-pr
LilyKensa Aug 25, 2024
02e19a2
Merge v7.45.1 into 1.21
Alexander01998 Sep 24, 2024
334e507
Merge v7.46pre1 into 1.21
Alexander01998 Sep 24, 2024
ccb1292
Merge v7.46pre2 into 1.21
Alexander01998 Sep 24, 2024
d944be9
Merge v7.46pre3 into 1.21
Alexander01998 Sep 24, 2024
ad61d02
Merge tag 'v7.46pre3' into 1.21
Alexander01998 Sep 24, 2024
c7d8d4e
Merge v7.46 into 1.21
Alexander01998 Sep 27, 2024
31ea40e
Merge pull request #8 from Wurst-Imperium/1.21
LilyKensa Sep 29, 2024
6d9f820
Optional AutoReconnectHack death screen button
LilyKensa Oct 2, 2024
f1e9d11
Merge pull request #9 from LilyKensa/optionalmenu-pr
LilyKensa Oct 2, 2024
1aed3af
Merge tag 'v7.46.1' into 1.21
Alexander01998 Oct 11, 2024
1f7d318
Merge pull request #11 from Wurst-Imperium/1.21
LilyKensa Oct 11, 2024
41ab6d2
Merge branch 'master' of github.com:LilyKensa/Wurst into autoplace-pr
LilyKensa Oct 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/main/java/net/wurstclient/hack/HackList.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ public final class HackList implements UpdateListener
public final AutoLeaveHack autoLeaveHack = new AutoLeaveHack();
public final AutoLibrarianHack autoLibrarianHack = new AutoLibrarianHack();
public final AutoEatHack autoEatHack = new AutoEatHack();
public final AutoPlaceHack autoPlaceHack = new AutoPlaceHack();
public final AutoFarmHack autoFarmHack = new AutoFarmHack();
public final AutoFishHack autoFishHack = new AutoFishHack();
public final AutoMineHack autoMineHack = new AutoMineHack();
Expand Down
105 changes: 105 additions & 0 deletions src/main/java/net/wurstclient/hacks/AutoPlaceHack.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Copyright (c) 2014-2024 Wurst-Imperium and contributors.
*
* This source code is subject to the terms of the GNU General Public
* License, version 3. If a copy of the GPL was not distributed with this
* file, You can obtain one at: https://www.gnu.org/licenses/gpl-3.0.txt
*/
package net.wurstclient.hacks;

import net.minecraft.client.gui.screen.ingame.HandledScreen;
import net.minecraft.client.network.ClientPlayerEntity;
import net.minecraft.item.BlockItem;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.hit.HitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.wurstclient.Category;
import net.wurstclient.SearchTags;
import net.wurstclient.events.UpdateListener;
import net.wurstclient.hack.Hack;
import net.wurstclient.settings.CheckboxSetting;
import net.wurstclient.util.BlockUtils;

@SearchTags({"bridge", "auto place"})
public final class AutoPlaceHack extends Hack implements UpdateListener
{
private final CheckboxSetting onlyBelowFeet =
new CheckboxSetting("Only Below Feet",
"Only place blocks when target block is 1 block below your feet.",
false);
private final CheckboxSetting fastPlace =
new CheckboxSetting("Always FastPlace",
"Builds as if FastPlace was enabled, even if it's not.", true);

public AutoPlaceHack()
{
super("AutoPlace");
setCategory(Category.BLOCKS);
addSetting(onlyBelowFeet);
addSetting(fastPlace);
}

@Override
public void onEnable()
{
EVENTS.add(UpdateListener.class, this);
}

@Override
public void onDisable()
{
EVENTS.remove(UpdateListener.class, this);
}

@Override
public void onUpdate()
{
if(MC.currentScreen instanceof HandledScreen)
return;

if(MC.itemUseCooldown != 0 && !fastPlace.isChecked())
return;
Alexander01998 marked this conversation as resolved.
Show resolved Hide resolved

ClientPlayerEntity player = MC.player;
assert player != null;
Comment on lines +66 to +67
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Avoid using assertions for null checks in production code.

Using assert statements for null checks is not recommended in production code because assertions may be disabled at runtime. Instead, consider implementing explicit null checks to prevent NullPointerException.

Apply this change:

-    assert player != null;
+    if (player == null)
+        return;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ClientPlayerEntity player = MC.player;
assert player != null;
ClientPlayerEntity player = MC.player;
if (player == null)
return;


// Item in hand is not a block
if(!(player.getInventory().getStack(player.getInventory().selectedSlot)
.getItem() instanceof BlockItem))
return;

HitResult hitResult = MC.crosshairTarget;
if(hitResult == null || hitResult.getType() != HitResult.Type.BLOCK)
return;

BlockHitResult blockHitResult = (BlockHitResult)hitResult;
if(blockHitResult.getSide() == Direction.UP
|| blockHitResult.getSide() == Direction.DOWN)
return;
Comment on lines +78 to +81
Copy link

@coderabbitai coderabbitai bot Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Consider allowing placement on the top and bottom faces.

Currently, the hack does not allow placing blocks when targeting the top or bottom face of a block. This might limit the usefulness of the hack in certain building scenarios.

Consider removing or adjusting this condition to allow more flexible block placement.

-    if(blockHitResult.getSide() == Direction.UP
-        || blockHitResult.getSide() == Direction.DOWN)
-        return;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
BlockHitResult blockHitResult = (BlockHitResult)hitResult;
if(blockHitResult.getSide() == Direction.UP
|| blockHitResult.getSide() == Direction.DOWN)
return;
BlockHitResult blockHitResult = (BlockHitResult)hitResult;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be made configurable in the settings. The PR author said they only want it to place blocks horizontally, but I agree this might limit its usefulness e.g. if you're trying to tower up.

Some different ideas for how the settings might work:

  • a single checkbox "Allow vertical placement"
  • an enum "Direction" ["Horizontal", "Vertical", "Both"]
  • multiple checkboxes "Place up", "Place down", "Place horizontal"
  • a long enum "Place directions" ["Horizontal", "Vertical", "Up only", "Down only", "Up/horizontal", "Down/horizontal", "All"]

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Alexander01998

Great suggestion! Making the placement directions configurable would enhance the flexibility of the AutoPlace hack.

You could implement this by adding an EnumSetting to allow users to select their preferred placement directions. Here's how you might do it:

private final EnumSetting<PlacementDirection> placementDirection =
    new EnumSetting<>("Placement Direction", PlacementDirection.values(), PlacementDirection.HORIZONTAL);

private enum PlacementDirection
{
    HORIZONTAL("Horizontal"),
    VERTICAL("Vertical"),
    BOTH("Both");

    private final String name;

    private PlacementDirection(String name)
    {
        this.name = name;
    }

    @Override
    public String toString()
    {
        return name;
    }
}

Then, adjust the onUpdate method to handle the selected option:

BlockHitResult blockHitResult = (BlockHitResult) hitResult;
Direction side = blockHitResult.getSide();

switch (placementDirection.getSelected())
{
    case HORIZONTAL:
        if (side == Direction.UP || side == Direction.DOWN)
            return;
        break;
    case VERTICAL:
        if (side.getAxis().isHorizontal())
            return;
        break;
    case BOTH:
        // Allow all directions
        break;
}

Alternatively, if you prefer multiple checkboxes for more granular control, you could add:

private final CheckboxSetting placeUp =
    new CheckboxSetting("Place Up", true);
private final CheckboxSetting placeDown =
    new CheckboxSetting("Place Down", true);
private final CheckboxSetting placeHorizontal =
    new CheckboxSetting("Place Horizontal", true);

And modify the onUpdate method accordingly:

BlockHitResult blockHitResult = (BlockHitResult) hitResult;
Direction side = blockHitResult.getSide();

if ((side == Direction.UP && !placeUp.isChecked()) ||
    (side == Direction.DOWN && !placeDown.isChecked()) ||
    (side.getAxis().isHorizontal() && !placeHorizontal.isChecked()))
    return;

This gives users the flexibility to enable or disable placement in specific directions based on their needs.

Let me know your thoughts on these options!


if(!BlockUtils.canBeClicked(blockHitResult.getBlockPos()))
return;
Alexander01998 marked this conversation as resolved.
Show resolved Hide resolved

BlockPos blockToPlacePos =
blockHitResult.getBlockPos().offset(blockHitResult.getSide());
if(!BlockUtils.getState(blockToPlacePos).isReplaceable())
return;

// Option: only below feet
if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
.down().getY() && onlyBelowFeet.isChecked())
return;
Comment on lines +91 to +94
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Simplify the condition for better readability.

The conditional statement can be simplified for clarity by checking onlyBelowFeet first before comparing positions.

Refactor the condition:

-    if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
-        .down().getY() && onlyBelowFeet.isChecked())
+    if (onlyBelowFeet.isChecked() && blockToPlacePos.getY() != MC.player.getBlockPos().down().getY())
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Option: only below feet
if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
.down().getY() && onlyBelowFeet.isChecked())
return;
// Option: only below feet
if (onlyBelowFeet.isChecked() && blockToPlacePos.getY() != MC.player.getBlockPos().down().getY())
return;


assert MC.interactionManager != null;
MC.interactionManager.interactItem(player, Hand.MAIN_HAND);
Comment on lines +96 to +97
Copy link

@coderabbitai coderabbitai bot Oct 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Redundant call to interactItem.

The call to MC.interactionManager.interactItem(player, Hand.MAIN_HAND); is unnecessary in this context because you are already interacting with the block using interactBlock. This might lead to unintended item interactions.

Remove the redundant method call:

-    MC.interactionManager.interactItem(player, Hand.MAIN_HAND);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
assert MC.interactionManager != null;
MC.interactionManager.interactItem(player, Hand.MAIN_HAND);
assert MC.interactionManager != null;

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

interactBlock and interactItem work in complicated and confusing ways. Sometimes both need to be called and sometimes even twice to match vanilla Minecraft behavior. I'd recommend instead using Wurst's utility net.wurstclient.util.InteractionSimulator whenever possible.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Alexander01998, thank you for the clarification. Using InteractionSimulator makes sense to ensure consistent behavior with vanilla Minecraft. I've updated the code to use InteractionSimulator:

@Override
public void onUpdate()
{
    if(MC.currentScreen instanceof HandledScreen)
        return;
    
    if(MC.itemUseCooldown != 0 && !fastPlace.isChecked())
        return;
    
    ClientPlayerEntity player = MC.player;
    assert player != null;
    
    // Item in hand is not a block
    if(!(player.getInventory().getStack(player.getInventory().selectedSlot)
        .getItem() instanceof BlockItem))
        return;
    
    HitResult hitResult = MC.crosshairTarget;
    if(hitResult == null || hitResult.getType() != HitResult.Type.BLOCK)
        return;
    
    BlockHitResult blockHitResult = (BlockHitResult)hitResult;
    if(blockHitResult.getSide() == Direction.UP
        || blockHitResult.getSide() == Direction.DOWN)
        return;
    
    if(!BlockUtils.canBeClicked(blockHitResult.getBlockPos()))
        return;
    
    BlockPos blockToPlacePos =
        blockHitResult.getBlockPos().offset(blockHitResult.getSide());
    if(!BlockUtils.getState(blockToPlacePos).isReplaceable())
        return;
    
    // Option: only below feet
    if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
        .down().getY() && onlyBelowFeet.isChecked())
        return;
    
    // Use InteractionSimulator to simulate block placement
    InteractionSimulator.rightClickBlock(blockHitResult, Hand.MAIN_HAND);
}

(•ᴗ•) A curious rabbit tilts its head in understanding.

ActionResult actionResult = MC.interactionManager.interactBlock(player,
Hand.MAIN_HAND, blockHitResult);
if(actionResult.isAccepted())
MC.player.swingHand(Hand.MAIN_HAND);

MC.itemUseCooldown = 4;
Alexander01998 marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +66 to +103
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Handle potential NullPointerException for MC.interactionManager.

Similar to the player entity, MC.interactionManager could be null. Relying on assertions might not prevent exceptions in production.

Implement a null check:

-    assert MC.interactionManager != null;
+    if (MC.interactionManager == null)
+        return;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
ClientPlayerEntity player = MC.player;
assert player != null;
// Item in hand is not a block
if(!(player.getInventory().getStack(player.getInventory().selectedSlot)
.getItem() instanceof BlockItem))
return;
HitResult hitResult = MC.crosshairTarget;
if(hitResult == null || hitResult.getType() != HitResult.Type.BLOCK)
return;
BlockHitResult blockHitResult = (BlockHitResult)hitResult;
if(blockHitResult.getSide() == Direction.UP
|| blockHitResult.getSide() == Direction.DOWN)
return;
if(!BlockUtils.canBeClicked(blockHitResult.getBlockPos()))
return;
BlockPos blockToPlacePos =
blockHitResult.getBlockPos().offset(blockHitResult.getSide());
if(!BlockUtils.getState(blockToPlacePos).isReplaceable())
return;
// Option: only below feet
if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
.down().getY() && onlyBelowFeet.isChecked())
return;
assert MC.interactionManager != null;
MC.interactionManager.interactItem(player, Hand.MAIN_HAND);
ActionResult actionResult = MC.interactionManager.interactBlock(player,
Hand.MAIN_HAND, blockHitResult);
if(actionResult.isAccepted())
MC.player.swingHand(Hand.MAIN_HAND);
MC.itemUseCooldown = 4;
ClientPlayerEntity player = MC.player;
assert player != null;
// Item in hand is not a block
if(!(player.getInventory().getStack(player.getInventory().selectedSlot)
.getItem() instanceof BlockItem))
return;
HitResult hitResult = MC.crosshairTarget;
if(hitResult == null || hitResult.getType() != HitResult.Type.BLOCK)
return;
BlockHitResult blockHitResult = (BlockHitResult)hitResult;
if(blockHitResult.getSide() == Direction.UP
|| blockHitResult.getSide() == Direction.DOWN)
return;
if(!BlockUtils.canBeClicked(blockHitResult.getBlockPos()))
return;
BlockPos blockToPlacePos =
blockHitResult.getBlockPos().offset(blockHitResult.getSide());
if(!BlockUtils.getState(blockToPlacePos).isReplaceable())
return;
// Option: only below feet
if(blockToPlacePos.getY() != BlockPos.ofFloored(MC.player.getPos())
.down().getY() && onlyBelowFeet.isChecked())
return;
if (MC.interactionManager == null)
return;
MC.interactionManager.interactItem(player, Hand.MAIN_HAND);
ActionResult actionResult = MC.interactionManager.interactBlock(player,
Hand.MAIN_HAND, blockHitResult);
if(actionResult.isAccepted())
MC.player.swingHand(Hand.MAIN_HAND);
MC.itemUseCooldown = 4;

}
}
1 change: 1 addition & 0 deletions src/main/resources/assets/wurst/translations/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"description.wurst.hack.autoleave": "Automatically leaves the server when your health is low.",
"description.wurst.hack.autolibrarian": "Automatically trains a villager to become a librarian that sells a specific enchanted book. You can set up an entire trading hall in no time by using this hack.",
"description.wurst.hack.autoeat": "Automatically eats food when necessary.",
"description.wurst.hack.autoplace": "Right click when your crosshair is pointing to a side face of a block.",
"description.wurst.setting.autoeat.target_hunger": "Tries to keep the hunger bar at or above this level, but only if it doesn't waste any hunger points.",
"description.wurst.setting.autoeat.min_hunger": "Always keeps the hunger bar at or above this level, even if it wastes some hunger points.\n6.5 - Cannot cause any waste with vanilla food items.\n10.0 - Completely ignores waste and just keeps the hunger bar full.",
"description.wurst.setting.autoeat.injured_hunger": "Fills the hunger bar to at least this level when you are injured, even if it wastes some hunger points.\n10.0 - fastest healing\n9.0 - slowest healing\n<9.0 - no healing\n<3.5 - no sprinting",
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/assets/wurst/translations/zh_tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"description.wurst.hack.autodrop": "自動丟棄你不想要的物品(有預設)。",
"description.wurst.hack.autoleave": "如果你的血量低於設定值,將會自動退出伺服器。",
"description.wurst.hack.autoeat": "當必要的時候將會自動進食。",
"description.wurst.hack.bridgeclick": "當你的準心對準方塊側面時自動按右鍵。",
"description.wurst.setting.autoeat.target_hunger": "嘗試將飢餓值保持在或高於此水平,但前提是它不會浪費任何飢餓值。",
"description.wurst.setting.autoeat.min_hunger": "始終將飢餓條保持在此水平或以上,即使它會浪費一些飢餓點。\n6.5 - 不會對香草食品造成任何浪費。\n10.0 - 完全忽略浪費並保持飢餓條充滿。",
"description.wurst.setting.autoeat.injured_hunger": "當你受傷時,將飢餓條填充到至少這個水平,即使它會浪費一些飢餓點。\n10.0 - 最快的治療\n9.0 - 最慢的治療\n<9.0 - 沒有治療\n<3.5 - 沒有衝刺",
Expand Down