diff --git a/CataloguedResources.txt b/CataloguedResources.txt index 698d20073..1621c8744 100644 --- a/CataloguedResources.txt +++ b/CataloguedResources.txt @@ -220,6 +220,7 @@ fence_gate fermented_spider_eye fern fire_charge +firework_rocket fishing_rod fletching_table flint diff --git a/src/main/java/adris/altoclef/AltoClefCommands.java b/src/main/java/adris/altoclef/AltoClefCommands.java index 24d0cbbc1..5bedcd02a 100644 --- a/src/main/java/adris/altoclef/AltoClefCommands.java +++ b/src/main/java/adris/altoclef/AltoClefCommands.java @@ -19,6 +19,7 @@ public AltoClefCommands() throws CommandException { new DepositCommand(), new StashCommand(), new GotoCommand(), + new GotoWithElytraCommand(), new IdleCommand(), new CoordsCommand(), new StatusCommand(), diff --git a/src/main/java/adris/altoclef/BotBehaviour.java b/src/main/java/adris/altoclef/BotBehaviour.java index 8d882eba7..450f39a38 100644 --- a/src/main/java/adris/altoclef/BotBehaviour.java +++ b/src/main/java/adris/altoclef/BotBehaviour.java @@ -141,6 +141,16 @@ public void setAllowWalkThroughFlowingWater(boolean value) { current().applyState(); } + //Way of disabling MLG and defense from a task + public boolean isDefenseDisabled() { + return current().disableDefence; + } + + public void disableDefence(boolean value) { + current().disableDefence = value; + current().applyState(); + } + public void setPauseOnLostFocus(boolean pauseOnLostFocus) { current().pauseOnLostFocus = pauseOnLostFocus; current().applyState(); @@ -263,6 +273,7 @@ class State { // Alto Clef params public boolean exclusivelyMineLogs; public boolean forceFieldPlayers; + public boolean disableDefence; public List> avoidDodgingProjectile = new ArrayList<>(); public List> excludeFromForceField = new ArrayList<>(); public List>> conversionSlots = new ArrayList<>(); @@ -306,6 +317,7 @@ public State(State toCopy) { conversionSlots.addAll(toCopy.conversionSlots); forceFieldPlayers = toCopy.forceFieldPlayers; escapeLava = toCopy.escapeLava; + disableDefence = toCopy.disableDefence; } } diff --git a/src/main/java/adris/altoclef/Playground.java b/src/main/java/adris/altoclef/Playground.java index 3fe73c356..52560ff95 100644 --- a/src/main/java/adris/altoclef/Playground.java +++ b/src/main/java/adris/altoclef/Playground.java @@ -14,6 +14,9 @@ import adris.altoclef.tasks.misc.*; import adris.altoclef.tasks.resources.TradeWithPiglinsTask; import adris.altoclef.tasks.examples.ExampleTask2; +import adris.altoclef.tasks.misc.EquipArmorTask; +import adris.altoclef.tasks.misc.PlaceBedAndSetSpawnTask; +import adris.altoclef.tasks.misc.RepairToolTask; import adris.altoclef.tasks.construction.PlaceSignTask; import adris.altoclef.tasks.speedrun.*; import adris.altoclef.tasks.stupid.BeeMovieTask; @@ -200,6 +203,10 @@ public static void TEMP_TEST_FUNCTION(AltoClef mod, String arg) { ItemTarget material = new ItemTarget("iron_ore", 4); mod.runUserTask(new SmeltInFurnaceTask(new SmeltTarget(target, material))); break; + case "repair": + //mod.runUserTask(new RepairToolTask(new ItemTarget("leather_chestplate", 1), new ItemTarget("golden_boots", 1) , new ItemTarget("iron_sword", 1))); + mod.runUserTask(new RepairToolTask()); + break; case "iron": mod.runUserTask(new ConstructIronGolemTask()); break; diff --git a/src/main/java/adris/altoclef/TaskCatalogue.java b/src/main/java/adris/altoclef/TaskCatalogue.java index 1d6fb6254..23d58910f 100644 --- a/src/main/java/adris/altoclef/TaskCatalogue.java +++ b/src/main/java/adris/altoclef/TaskCatalogue.java @@ -276,6 +276,7 @@ public class TaskCatalogue { alias("eye_of_ender", "ender_eye"); shapedRecipe2x2("fermented_spider_eye", Items.FERMENTED_SPIDER_EYE, 1, "brown_mushroom", "sugar", o, "spider_eye"); shapedRecipe3x3("fire_charge", Items.FIRE_CHARGE, 3, o, "blaze_powder", o, o, "coal", o, o, "gunpowder", o); + shapedRecipe2x2("firework_rocket", Items.FIREWORK_ROCKET, 3, "paper", "gunpowder", o, o); shapedRecipe2x2("flower_banner_pattern", Items.FLOWER_BANNER_PATTERN, 1, "paper", "oxeye_daisy", o, o); simple("magma_cream", Items.MAGMA_CREAM, CollectMagmaCreamTask::new); // Slabs + Stairs + Walls diff --git a/src/main/java/adris/altoclef/chains/MLGBucketFallChain.java b/src/main/java/adris/altoclef/chains/MLGBucketFallChain.java index e0202aacd..5dc1a6079 100644 --- a/src/main/java/adris/altoclef/chains/MLGBucketFallChain.java +++ b/src/main/java/adris/altoclef/chains/MLGBucketFallChain.java @@ -7,6 +7,7 @@ import adris.altoclef.tasksystem.TaskRunner; import adris.altoclef.util.time.TimerGame; import adris.altoclef.util.helpers.LookHelper; +import adris.altoclef.util.helpers.EntityHelper; import baritone.api.utils.Rotation; import baritone.api.utils.input.Input; import net.minecraft.entity.effect.StatusEffects; @@ -119,10 +120,10 @@ public boolean isChorusFruiting() { } public boolean isFallingOhNo(AltoClef mod) { - if (!mod.getModSettings().shouldAutoMLGBucket()) { + if (!mod.getModSettings().shouldAutoMLGBucket() || mod.getBehaviour().isDefenseDisabled()) { return false; } - if (mod.getPlayer().isSwimming() || mod.getPlayer().isTouchingWater() || mod.getPlayer().isOnGround() || mod.getPlayer().isClimbing()) { + if (EntityHelper.isGrounded(mod)) { // We're grounded. return false; } diff --git a/src/main/java/adris/altoclef/chains/MobDefenseChain.java b/src/main/java/adris/altoclef/chains/MobDefenseChain.java index 7aa61d5ac..a0964f40b 100644 --- a/src/main/java/adris/altoclef/chains/MobDefenseChain.java +++ b/src/main/java/adris/altoclef/chains/MobDefenseChain.java @@ -80,7 +80,7 @@ private float getPriorityInner(AltoClef mod) { return Float.NEGATIVE_INFINITY; } - if (!mod.getModSettings().isMobDefense()) { + if (!mod.getModSettings().isMobDefense() || mod.getBehaviour().isDefenseDisabled()) { return Float.NEGATIVE_INFINITY; } diff --git a/src/main/java/adris/altoclef/commands/GotoWithElytraCommand.java b/src/main/java/adris/altoclef/commands/GotoWithElytraCommand.java new file mode 100644 index 000000000..31dde0698 --- /dev/null +++ b/src/main/java/adris/altoclef/commands/GotoWithElytraCommand.java @@ -0,0 +1,21 @@ +package adris.altoclef.commands; + +import adris.altoclef.AltoClef; +import adris.altoclef.commandsystem.Arg; +import adris.altoclef.commandsystem.ArgParser; +import adris.altoclef.commandsystem.Command; +import adris.altoclef.commandsystem.CommandException; +import adris.altoclef.tasks.movement.GetToXZWithElytraTask; + +public class GotoWithElytraCommand extends Command { + public GotoWithElytraCommand() throws CommandException { + super("elytra", "Tell bot to travel to a set of coordinates using Elytra", new Arg(Integer.class, "x"), new Arg(Integer.class, "z")); + } + + @Override + protected void call(AltoClef mod, ArgParser parser) throws CommandException { + int x = parser.get(Integer.class); + int z = parser.get(Integer.class); + mod.runUserTask(new GetToXZWithElytraTask(x,z), this::finish); + } +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/misc/RepairToolTask.java b/src/main/java/adris/altoclef/tasks/misc/RepairToolTask.java new file mode 100644 index 000000000..e93b1724e --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/misc/RepairToolTask.java @@ -0,0 +1,183 @@ +package adris.altoclef.tasks.misc; + +import adris.altoclef.AltoClef; +import adris.altoclef.Debug; +import adris.altoclef.tasks.entity.KillEntityTask; +import adris.altoclef.tasks.movement.GetToBlockTask; +import adris.altoclef.tasks.movement.TimeoutWanderTask; +import adris.altoclef.tasks.movement.GetToEntityTask; +import adris.altoclef.tasks.entity.DoToClosestEntityTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.helpers.StorageHelper; +import adris.altoclef.util.slots.Slot; +import adris.altoclef.util.slots.PlayerSlot; +import adris.altoclef.util.helpers.ItemHelper; +import net.minecraft.item.Items; +import baritone.api.utils.input.Input; +import net.minecraft.entity.mob.ZombieEntity; +import net.minecraft.entity.ExperienceOrbEntity; +import adris.altoclef.util.time.TimerGame; +import adris.altoclef.util.helpers.LookHelper; +import baritone.api.utils.Rotation; +import net.minecraft.entity.Entity; +import net.minecraft.enchantment.EnchantmentHelper; +import net.minecraft.enchantment.Enchantments; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.item.ItemStack; +import java.util.List; +import java.util.Optional; +import java.util.Arrays; + +public class RepairToolTask extends Task { + + private final ItemTarget[] _toRepair; + + private boolean _finished; + private final TimerGame _throwTimer = new TimerGame(0.5); + + public RepairToolTask(ItemTarget... toRepair) { + _toRepair = toRepair; + } + public RepairToolTask() { //If this task is called without itemtarget, repair anything we can + this( + new ItemTarget(ItemHelper.NETHERITE_ARMORS), + new ItemTarget(ItemHelper.NETHERITE_TOOLS), + new ItemTarget(Items.ELYTRA), + new ItemTarget(ItemHelper.DIAMOND_ARMORS), + new ItemTarget(ItemHelper.DIAMOND_TOOLS), + new ItemTarget(ItemHelper.IRON_ARMORS), + new ItemTarget(ItemHelper.IRON_TOOLS), + new ItemTarget(ItemHelper.GOLDEN_ARMORS), + new ItemTarget(ItemHelper.GOLDEN_TOOLS), + new ItemTarget(ItemHelper.STONE_TOOLS), + new ItemTarget(ItemHelper.LEATHER_ARMORS), + new ItemTarget(ItemHelper.WOODEN_TOOLS), + new ItemTarget(Items.FISHING_ROD), + new ItemTarget(Items.FLINT_AND_STEEL), + new ItemTarget(Items.CARROT_ON_A_STICK), + new ItemTarget(Items.SHEARS), + new ItemTarget(Items.BOW), + new ItemTarget(Items.SHIELD), + new ItemTarget(Items.TRIDENT), + new ItemTarget(Items.CROSSBOW), + new ItemTarget(Items.WARPED_FUNGUS_ON_A_STICK), + new ItemTarget(Items.BOW) + ); + } + @Override + protected void onStart(AltoClef mod) { + _throwTimer.reset(); + } + + @Override + protected Task onTick(AltoClef mod) { + //We start this task by filtering out every item type that we can't repair : + //All items without mending or with no damage + ItemTarget[] shouldRepair = Arrays.stream(_toRepair).filter(target -> needRepair(mod, target)).toArray(ItemTarget[]::new); + + //After that, we get the first item type to repair on the list + Optional itemTargetOPTRepair = Arrays.stream(shouldRepair).findFirst(); + + if (itemTargetOPTRepair.isPresent()) { //If the list is not empty + ItemTarget itemTargetRepair = itemTargetOPTRepair.get(); //We get the (real) first item on the list + + List slotRepairs = mod.getItemStorage().getSlotsWithItemPlayerInventory(false, itemTargetRepair.getMatches()); //And we get a list of every slot with that item + + Optional slotRepairTarget = Optional.empty(); + for (Slot couldRepair : slotRepairs) { + if (slotRepairTarget.isEmpty() && StorageHelper.getItemStackInSlot(couldRepair).getDamage() != 0) { //if we can repair it + if (EnchantmentHelper.get(StorageHelper.getItemStackInSlot(couldRepair)).containsKey(Enchantments.MENDING)) { //and it have mending + slotRepairTarget = Optional.of(couldRepair); //Replace the placeholder slot with the slot we found + } + } + } + if (slotRepairTarget.isPresent()) { //If we found our slot, we can now repair the item ! + final Slot ItemToEquip = slotRepairTarget.get(); + setDebugState("Repairing " + StorageHelper.getItemStackInSlot(ItemToEquip).getName().getString()); + if (!_throwTimer.elapsed()){ //If we just used a experience bottle, get the item in our hand to repair + mod.getSlotHandler().forceEquipSlot(ItemToEquip); + return null; + } + //Get the nearest experience orb + boolean isExpPresent = mod.getEntityTracker().entityFound(ExperienceOrbEntity.class); + if (isExpPresent) { //if there is one + setDebugState("Collecting EXP Orbs"); + return new DoToClosestEntityTask(entity -> { //Get to the entity + if (entity.isInRange(mod.getPlayer(), 3)) { //and if the orb is near the player + mod.getSlotHandler().forceEquipSlot(ItemToEquip); //get the item in our hand to repair the item + } + return new GetToEntityTask(entity, 0); + }, ExperienceOrbEntity.class); + } + if (mod.getItemStorage().hasItem(Items.EXPERIENCE_BOTTLE)) { //if we have some experience bottle + setDebugState("Throwing EXP Bottles for EXP"); + if (_throwTimer.elapsed()) { //the timer for throwing a experience bottle + if (!LookHelper.isLookingAt(mod, new Rotation(0, 90))) { + LookHelper.lookAt(mod, new Rotation(0, 90)); //Look at our feet + } + mod.getSlotHandler().forceEquipItem(Items.EXPERIENCE_BOTTLE); //equip it + mod.getInputControls().tryPress(Input.CLICK_RIGHT); //and throw it + _throwTimer.reset(); + } + return null; + } + + setDebugState("Killing Zombies for EXP"); + return new DoToClosestEntityTask(KillEntityTask::new, ZombieEntity.class); + } + } //If there is no items in the list of itemtype to repair, it means there is nothing to repair :) + setDebugState("Done"); + _finished = true; + return null; + } + + @Override + public boolean isFinished(AltoClef mod) { + return _finished; + } + //Check if a type of item can be repaired. + public static boolean needRepair(AltoClef mod, ItemTarget target) { + List slotRepair = mod.getItemStorage().getSlotsWithItemPlayerInventory(false, target.getMatches()); + for (Slot couldRepair : slotRepair) { + if (StorageHelper.getItemStackInSlot(couldRepair).getDamage() != 0) { + if (EnchantmentHelper.get(StorageHelper.getItemStackInSlot(couldRepair)).containsKey(Enchantments.MENDING)) { + return true; + } + } + } + return false; + } + //Will get the durability of an item in accordance of the ItemTarget. + //Return the durability of one of the item, or -1 if all targeted items is repaired or doesn't have the targeted item + public static int getDurabilityOfRepairableItem(AltoClef mod, ItemTarget target) { + List slotRepairs = mod.getItemStorage().getSlotsWithItemPlayerInventory(false, target.getMatches()); + for (Slot couldRepair : slotRepairs) { + if (StorageHelper.getItemStackInSlot(couldRepair).getDamage() != 0) { + if (EnchantmentHelper.get(StorageHelper.getItemStackInSlot(couldRepair)).containsKey(Enchantments.MENDING)) { + return StorageHelper.getItemStackInSlot(couldRepair).getMaxDamage() - StorageHelper.getItemStackInSlot(couldRepair).getDamage(); + } + } + } + return -1; + } + @Override + protected void onStop(AltoClef mod, Task interruptTask) { + + } + + @Override + protected boolean isEqual(Task other) { + if (other instanceof RepairToolTask task) { + return Arrays.equals(task._toRepair, _toRepair); + } + return false; + } + + @Override + protected String toDebugString() { + return "Repairing: " + Arrays.toString(_toRepair); + } + +} \ No newline at end of file diff --git a/src/main/java/adris/altoclef/tasks/movement/GetToXZWithElytraTask.java b/src/main/java/adris/altoclef/tasks/movement/GetToXZWithElytraTask.java new file mode 100644 index 000000000..68119c455 --- /dev/null +++ b/src/main/java/adris/altoclef/tasks/movement/GetToXZWithElytraTask.java @@ -0,0 +1,251 @@ +package adris.altoclef.tasks.movement; + +import adris.altoclef.AltoClef; +import adris.altoclef.Debug; +import adris.altoclef.TaskCatalogue; +import adris.altoclef.tasks.slot.MoveItemToSlotFromInventoryTask; +import adris.altoclef.tasks.misc.RepairToolTask; +import adris.altoclef.tasks.slot.ClickSlotTask; +import adris.altoclef.tasks.slot.EnsureFreeInventorySlotTask; +import adris.altoclef.tasksystem.Task; +import adris.altoclef.util.ItemTarget; +import adris.altoclef.util.time.TimerGame; +import adris.altoclef.util.helpers.LookHelper; +import adris.altoclef.util.helpers.StorageHelper; +import adris.altoclef.util.helpers.WorldHelper; +import adris.altoclef.util.helpers.EntityHelper; +import adris.altoclef.util.slots.PlayerSlot; +import adris.altoclef.util.slots.Slot; +import baritone.api.utils.Rotation; +import baritone.api.utils.input.Input; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.math.Vec3d; +import java.util.List; + +public class GetToXZWithElytraTask extends Task { + private static final int CLOSE_ENOUGH_TO_WALK = 128; //If the distance to the goal is less than this, it will walk + private static final int MINIMAL_ELYTRA_DURABILITY = 35; //Will land if the durability left is under that + private static final int MINIMAL_FIREWORKS = 16; //Minimal number of fireworks before starting flying + private static final int FIREWORKS_GOAL = 32; //Number of fireworks to get if needed + private static final int FLY_LEVEL = 325; //319 is the world's height limit in 1.18 + + private static final int LOOK_DISTANCE = 6; //If the target's distance is lower than this value, + //The bot will not try to look at the target while flying + + + private static final int LAND_TARGET_DISTANCE = 12; //Will not use fireworks when the target's distance is lower than that + + private final int _x, _z; + private boolean _isMovingElytra = false; + private boolean _isCollectingFireWork = false; + private boolean _isFlyRunning = false; + private boolean _repairElytra = false; + private double _oldCoordsY; + private int _yGoal = 0; + private int _fx = 0; + private int _fz = 0; + private final TimerGame _fireWorkTimer = new TimerGame(3); + private final TimerGame _messageProgessTimer = new TimerGame(3); + private final TimerGame _getToSurfaceTimer = new TimerGame(2); + private final TimerGame _jumpTimer = new TimerGame(0.1); + + public GetToXZWithElytraTask(int x, int z) { + _x = x; + _z = z; + } + @Override + protected void onStart(AltoClef mod) { + _jumpTimer.reset(); + _fireWorkTimer.reset(); + _messageProgessTimer.reset(); + // We disable/enable mob defense intermittently + mod.getBehaviour().push(); + } + + @Override + protected Task onTick(AltoClef mod) { + double dist = mod.getPlayer().getPos().distanceTo(new Vec3d(_x, mod.getPlayer().getPos().y, _z)); //Calculate distance + if (!_isFlyRunning) { //If we are already flying, jump that code section + _fx = 0; + _fz = 0; + mod.getBehaviour().disableDefence(false); //Enable mob defence + if (dist < CLOSE_ENOUGH_TO_WALK) { //We are near our goal + setDebugState("Walking to goal"); + return new GetToXZTask(_x, _z); //Get to our goal + } + //If we don't have elytra, walk to our goal + if (!mod.getItemStorage().hasItem(Items.ELYTRA) && !_isMovingElytra && StorageHelper.getItemStackInSlot(PlayerSlot.ARMOR_CHESTPLATE_SLOT).getItem() != Items.ELYTRA) { + setDebugState("Walking to goal, since we don't have an elytra"); + return new GetToXZTask(_x, _z); + } + + if (_repairElytra && RepairToolTask.needRepair(mod, new ItemTarget(Items.ELYTRA))) { //If we can repair it + setDebugState("Repairing elytra"); + return new RepairToolTask(new ItemTarget(Items.ELYTRA)); //Run the task to repair it + } else { + _repairElytra = false; + } + int durabilityLeft = RepairToolTask.getDurabilityOfRepairableItem(mod, new ItemTarget(Items.ELYTRA)); //Get the elytra durability + + if (durabilityLeft < MINIMAL_ELYTRA_DURABILITY && durabilityLeft != -1) { //If we need to repair it before flying + if (RepairToolTask.needRepair(mod, new ItemTarget(Items.ELYTRA))) { + _repairElytra = true; + return null; + } + setDebugState("Walking to goal, elytra is broken / will broke"); + return new GetToXZTask(_x, _z); //Walk to our goal + } + + //Get some fireworks if doesn't have many + if ((mod.getItemStorage().getItemCount(Items.FIREWORK_ROCKET) < MINIMAL_FIREWORKS || _isCollectingFireWork) && mod.getItemStorage().getItemCount(Items.FIREWORK_ROCKET) < FIREWORKS_GOAL) { + _isCollectingFireWork = true; + setDebugState("Getting some fireworks"); + return TaskCatalogue.getItemTask(Items.FIREWORK_ROCKET, FIREWORKS_GOAL); + } + _isCollectingFireWork = false; + + //Equip elytra, if didn't equipped, + setDebugState("Equipping elytra"); + if (StorageHelper.getItemStackInSlot(PlayerSlot.ARMOR_CHESTPLATE_SLOT).getItem() != Items.ELYTRA) { + //EquipArmorTask(Items.ELYTRA) was crashing the game because of "class net.minecraft.item.ElytraItem cannot be cast to class net.minecraft.item.ArmorItem" + _isMovingElytra = true; + return new MoveItemToSlotFromInventoryTask(new ItemTarget(Items.ELYTRA, 1), PlayerSlot.ARMOR_CHESTPLATE_SLOT);//So we move it manually + } + _isMovingElytra = false; + + //We move to the surface, because we can't fly in caves :) + setDebugState("Moving to the surface"); + + int y = getGroundHeightWithRadius(mod, (int)mod.getPlayer().getPos().x, (int)mod.getPlayer().getPos().z); //get the highest block near the player + if (_yGoal == 0 || _yGoal < mod.getPlayer().getPos().y) { //If we don't have a goal or the player is higher than our current goal + _yGoal = y; //Set the new goal + } + if (y > mod.getPlayer().getPos().y || !_getToSurfaceTimer.elapsed()) { //if the highest block is higher than the player or the _getToSurfaceTimer isn't elapsed + if (y > mod.getPlayer().getPos().y) { //if the highest block is higher than the player + _getToSurfaceTimer.reset(); //reset the timer + } + return new GetToYTask(_yGoal+1); //Get to the surface + } + _yGoal = 0; + _fireWorkTimer.forceElapse(); + } + _isFlyRunning = true; //We will now try to fly, we don't need to check the code before this for now. + mod.getBehaviour().disableDefence(true); //Disable MobDefence and MLG, because it get interupted by that + + //Get the elytra's durability + ItemStack elytraItem = StorageHelper.getItemStackInSlot(PlayerSlot.ARMOR_CHESTPLATE_SLOT); + int durabilityLeft = elytraItem.getMaxDamage()-elytraItem.getDamage(); + + float yaw = LookHelper.getLookRotation(mod,new Vec3d(_x, 1, _z)).getYaw(); //The players's direction + float pitch; //Players's pitch, will be set later + + if (mod.getPlayer().getPos().y > FLY_LEVEL-2) { //When flying higher than our flylevel + if (_oldCoordsY > mod.getPlayer().getPos().y && _fireWorkTimer.elapsed()) { + pitch = (float)10; //Look a bit down, when flying down + } else { + pitch = (float)-10; //If we are flying up or using a firework, look a bit up + } + } else { + pitch = (float)-40; //When flying under the world's height limit, we need to go up, so we look up + } + + setDebugState("Going to "+_x+" "+_z); + + if (durabilityLeft < MINIMAL_ELYTRA_DURABILITY) { //If the durability is below 35, we need to get on the ground safely before the elytra break + if ((mod.getPlayer().getPos().distanceTo(new Vec3d(_fx, mod.getPlayer().getPos().y, _fz)) > 30) || _fx == 0 || _fz == 0) { //if we need to set the "land point" + _fx = (int)mod.getPlayer().getPos().x; //Set a landing point where we are + _fz = (int)mod.getPlayer().getPos().z; + } + if (_fx != 0 && _fz != 0) { //If there is a landing point + dist = mod.getPlayer().getPos().distanceTo(new Vec3d(_fx, mod.getPlayer().getPos().y, _fz)); //Recalculate distance for the landing point + yaw = LookHelper.getLookRotation(mod,new Vec3d(_fx, 1, _fz)).getYaw(); //And the players's direction too + //Setting that will trigget the bot to land + } + } + + if (dist > 15) { //Things to do when flying (or trying to fly) + if (_jumpTimer.elapsed()) {//every 0.1 sec: jump, to enable elytra + mod.getInputControls().tryPress(Input.JUMP); + _jumpTimer.reset(); + } + //If we can use firework rocket, if we have one, and are under the flylevel + if (_fireWorkTimer.elapsed() && mod.getPlayer().getPos().y < FLY_LEVEL && mod.getItemStorage().hasItem(Items.FIREWORK_ROCKET)) { + if (mod.getSlotHandler().forceEquipItem(Items.FIREWORK_ROCKET)) {//try to equip the item + mod.getInputControls().tryPress(Input.CLICK_RIGHT); //and use it + _fireWorkTimer.reset(); + pitch = (float)-10; + } + } + //Log a message in chat + if (_messageProgessTimer.elapsed()) { + Debug.logMessage("Distance: "+(int)dist+", Elytra durability: "+durabilityLeft); + _messageProgessTimer.reset(); + } + } else { //if the distance is under 15, we need to land slowly + setDebugState("Landing..."); + if (getGroundHeightWithRadius(mod, (int)mod.getPlayer().getPos().x, (int)mod.getPlayer().getPos().z)+50 > mod.getPlayer().getPos().y) { + pitch = (float)20; //look a bit down + } else { + pitch = (float)50; //look down, to land faster + } + } + + if (dist > LOOK_DISTANCE) { //if the distance is upper than the look distance + if (!LookHelper.isLookingAt(mod, new Rotation(yaw, pitch))) { + LookHelper.lookAt(mod, new Rotation(yaw, pitch)); //Look at the target + } + + } + //if we have landed, and the distance is under the LAND_TARGET_DISTANCE or we don't have any fireworks + if (EntityHelper.isGrounded(mod) && (dist < LAND_TARGET_DISTANCE || !mod.getItemStorage().hasItem(Items.FIREWORK_ROCKET))) { + if (StorageHelper.getItemStackInSlot(PlayerSlot.ARMOR_CHESTPLATE_SLOT).getItem() == Items.ELYTRA) { //Unequip elytra + return new ClickSlotTask(PlayerSlot.ARMOR_CHESTPLATE_SLOT); //Click on the elytra in the armor slot + } else if (!StorageHelper.getItemStackInCursorSlot().isEmpty()){ //Once it's in the cursor slot + List airslot = mod.getItemStorage().getSlotsWithItemPlayerInventory(false, Items.AIR); //Click on a empty inv slot + if (airslot.isEmpty()) { + return new EnsureFreeInventorySlotTask(); //If there is no space + } else { + return new ClickSlotTask(airslot.get(0)); //Click on the slot to put elytra back in inventory + } + } else { + _isFlyRunning = false; //Recheck the code at the start of this task to + } + } + _oldCoordsY = mod.getPlayer().getPos().y; //save the old player y position + return null; + } + @Override + protected void onStop(AltoClef mod, Task interruptTask) { + mod.getBehaviour().pop(); + } + + @Override + protected boolean isEqual(Task other) { + if (other instanceof GetToXZWithElytraTask task) { + return task._x == _x && task._z == _z; + } + return false; + } + + @Override + public boolean isFinished(AltoClef mod) { + return WorldHelper.inRangeXZ(mod.getPlayer(), new Vec3d(_x, mod.getPlayer().getY(), _z), 2) && !_isFlyRunning; + } + @Override + protected String toDebugString() { + return "Moving using Elytra"; + } + private int getGroundHeightWithRadius(AltoClef mod, int x, int z) { + int topY = 0; + for (int x2 = 5; x2 >= -5; --x2) { + for (int z2 = 5; z2 >= -5; --z2) { + int tmpy = WorldHelper.getGroundHeight(mod,x+x2,z+z2); + if (tmpy > topY) { + topY = tmpy; + } + } + } + return topY; + } +} diff --git a/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java b/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java index 34cea2dab..2c489009f 100644 --- a/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java +++ b/src/main/java/adris/altoclef/tasks/movement/MLGBucketTask.java @@ -487,7 +487,7 @@ protected void onStop(AltoClef mod, Task interruptTask) { @Override public boolean isFinished(AltoClef mod) { - return mod.getPlayer().isSwimming() || mod.getPlayer().isTouchingWater() || mod.getPlayer().isOnGround() || mod.getPlayer().isClimbing(); + return EntityHelper.isGrounded(mod); } @Override diff --git a/src/main/java/adris/altoclef/tasksystem/ITaskRequiresGrounded.java b/src/main/java/adris/altoclef/tasksystem/ITaskRequiresGrounded.java index dac5ed1a3..f2944ce77 100644 --- a/src/main/java/adris/altoclef/tasksystem/ITaskRequiresGrounded.java +++ b/src/main/java/adris/altoclef/tasksystem/ITaskRequiresGrounded.java @@ -1,7 +1,7 @@ package adris.altoclef.tasksystem; import adris.altoclef.AltoClef; - +import adris.altoclef.util.helpers.EntityHelper; /** * Some tasks may mess up royally if we interrupt them while mid air. * For instance, if we're doing some parkour and a baritone task is stopped, @@ -12,6 +12,6 @@ public interface ITaskRequiresGrounded extends ITaskCanForce { default boolean shouldForce(AltoClef mod, Task interruptingCandidate) { if (interruptingCandidate instanceof ITaskOverridesGrounded) return false; - return !(mod.getPlayer().isOnGround() || mod.getPlayer().isSwimming() || mod.getPlayer().isTouchingWater() || mod.getPlayer().isClimbing()); + return !(EntityHelper.isGrounded(mod)); } } diff --git a/src/main/java/adris/altoclef/util/helpers/EntityHelper.java b/src/main/java/adris/altoclef/util/helpers/EntityHelper.java index d3e9070b7..c2e460a5f 100644 --- a/src/main/java/adris/altoclef/util/helpers/EntityHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/EntityHelper.java @@ -62,6 +62,16 @@ public static boolean isTradingPiglin(Entity entity) { return false; } + /** + * Return true if the entity is on ground (or in water) + */ + public static boolean isGrounded(AltoClef mod, Entity entity) { + return entity.isSwimming() || entity.isTouchingWater() || entity.isOnGround(); + } + public static boolean isGrounded(AltoClef mod) { + return isGrounded(mod,mod.getPlayer()); + } + /** * Calculate the resulting damage dealt to a player as a result of some damage. * If this player were to receive this damage, the player's health will be subtracted by the resulting value. diff --git a/src/main/java/adris/altoclef/util/helpers/WorldHelper.java b/src/main/java/adris/altoclef/util/helpers/WorldHelper.java index 091751e00..dbcf79977 100644 --- a/src/main/java/adris/altoclef/util/helpers/WorldHelper.java +++ b/src/main/java/adris/altoclef/util/helpers/WorldHelper.java @@ -104,7 +104,8 @@ static Dimension getCurrentDimension() { static boolean isSolid(AltoClef mod, BlockPos pos) { - return mod.getWorld().getBlockState(pos).isSolidBlock(mod.getWorld(), pos); + BlockState state = mod.getWorld().getBlockState(pos); + return state.isSolidBlock(mod.getWorld(), pos) || state.hasSolidTopSurface(mod.getWorld(), pos, mod.getPlayer()); } /** @@ -369,8 +370,8 @@ static boolean isChest(Block b) { return b instanceof ChestBlock || b instanceof EnderChestBlock; } - static boolean isBlock(AltoClef mod, BlockPos pos, Block block) { - return mod.getWorld().getBlockState(pos).getBlock() == block; + static boolean isBlock(AltoClef mod, BlockPos pos, Block... blocks) { + return mod.getBlockTracker().blockIsValid(pos, blocks); } static boolean canSleep() { diff --git a/usage.md b/usage.md index 9f3dc72a9..fefb0298e 100644 --- a/usage.md +++ b/usage.md @@ -22,9 +22,9 @@ Commands are prefixed with `@`. Here's a list along with their functions: | `deposit [items... = ]` | Deposit a list of items in the nearest container, making a chest if we can't find one. Will only deposit items present in the bot's inventory (at the time of running this command). Leave out the list to deposit every non-tool/armor item in the bot's inventory. Useful with command chaining. | `@deposit diamond 3` `@deposit [cobblestone 1000, raw_iron 100]` `@deposit` | | `stash {x0} {y0} {z0} {x1} {y0} {z1} [items... = ]` | Same as `@deposit`, but you specify an area from `(x0, y0, z0)` to `(x1, y1, z1)` where the bot stores the item list (these coordinates being a chest stash). Just like `@deposit`, providing no items simply deposits everything in the bots inventory. | `@stash 100 64 100 200 70 100 diamond 3` | | `goto {x} {y} {z} {dimension=}` | Goes to (`x`,`y`, `z`) in a given `dimension`. Travels to `dimension` if not there already. Can also omit coordinates to just go to a dimension. Passing 2 values as coordinates goes to X Z coordinates instead. | `@goto 100 64 100 overworld` `@goto nether` `@goto 100 100` | +| `elytra [x] [z]` | Goes to (`[x]`, `[z]`) using an elytra, it will do the same thing as `goto [x] [z]` if we don't have one| `@elytra 1000 500` | | `inventory {item=}` | Prints the bots inventory, OR how many items of a specific type the bot has. Mostly useful when running through `/msg`. | `/msg Bot inventory` `/msg Bot inventory cobblestone` | | `locate_structure {structure_type}` | Attempts to locate a `structure_type` structure. Can find strongholds or desert temples. | `@locate_structure stronghold`, `@locate_structure desert_temple` | -| `punk {player}` | Attacks `player`. | | | `reload_settings` | Reloads the local settings file. Run this every time you want your settings to be updated. | | | `gamma {brightness=1}` | Sets the game's gamma. Useful for testing. 0 is "Moody" and 1 is "Bright", and you can go beyond to enable fullbright. | `@gamma 1000` | | `status` | Prints the status of the currently executing command. Mostly useful when running through `/msg`. | |