diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java index 076f8f395..44701b798 100644 --- a/src/api/java/baritone/api/Settings.java +++ b/src/api/java/baritone/api/Settings.java @@ -1420,6 +1420,16 @@ public final class Settings { */ public final Setting elytraMinimumDurability = new Setting<>(5); + /** + * The minimum fireworks before landing early for safety + */ + public final Setting elytraMinFireworksBeforeLanding = new Setting<>(5); + + /** + * Automatically land when elytra is almost out of durability, or almost out of fireworks + */ + public final Setting elytraAllowEmergencyLand = new Setting<>(true); + /** * Time between culling far away chunks from the nether pathfinder chunk cache */ diff --git a/src/main/java/baritone/process/ElytraProcess.java b/src/main/java/baritone/process/ElytraProcess.java index a93980cbd..c6c41881d 100644 --- a/src/main/java/baritone/process/ElytraProcess.java +++ b/src/main/java/baritone/process/ElytraProcess.java @@ -47,6 +47,9 @@ import it.unimi.dsi.fastutil.longs.LongOpenHashSet; import net.minecraft.block.Block; import net.minecraft.block.state.IBlockState; import net.minecraft.init.Blocks; +import net.minecraft.init.Items; +import net.minecraft.item.ItemStack; +import net.minecraft.util.NonNullList; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Vec3d; @@ -112,11 +115,21 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); } - if (ctx.player().isElytraFlying() && this.state != State.LANDING && this.behavior.pathManager.isComplete()) { + boolean safetyLanding = false; + if (ctx.player().isElytraFlying() && shouldLandForSafety()) { + if (Baritone.settings().elytraAllowEmergencyLand.value) { + logDirect("Emergency landing - almost out of elytra durability or fireworks"); + safetyLanding = true; + } else { + logDirect("almost out of elytra durability or fireworks, but I'm going to continue since elytraAllowEmergencyLand is false"); + } + } + if (ctx.player().isElytraFlying() && this.state != State.LANDING && (this.behavior.pathManager.isComplete() || safetyLanding)) { final BetterBlockPos last = this.behavior.pathManager.path.getLast(); - if (last != null && ctx.player().getDistanceSqToCenter(last) < (48 * 48) && !goingToLandingSpot) { + logDirect((last != null) + " " + this.state + " " + safetyLanding + " " + goingToLandingSpot); + if (last != null && (ctx.player().getDistanceSqToCenter(last) < (48 * 48) || safetyLanding) && (!goingToLandingSpot || (safetyLanding && this.landingSpot == null))) { logDirect("Path complete, picking a nearby safe landing spot..."); - BetterBlockPos landingSpot = findSafeLandingSpot(last); + BetterBlockPos landingSpot = findSafeLandingSpot(ctx.playerFeet()); // if this fails we will just keep orbiting the last node until we run out of rockets or the user intervenes if (landingSpot != null) { this.pathTo0(landingSpot, true); @@ -185,6 +198,11 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro } if (this.state == State.LOCATE_JUMP) { + if (shouldLandForSafety()) { + logDirect("Not taking off, because elytra durability or fireworks are so low that I would immediately emergency land anyway."); + onLostControl(); + return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL); + } if (this.goal == null) { this.goal = new GoalYLevel(31); } @@ -338,6 +356,25 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro this.pathTo(new BlockPos(x, y, z)); } + private boolean shouldLandForSafety() { + ItemStack chest = ctx.player().inventory.armorInventory.get(2); + if (chest.getItem() != Items.ELYTRA || chest.getItem().getMaxDamage() - chest.getItemDamage() < Baritone.settings().elytraMinimumDurability.value) { + // elytrabehavior replaces when durability <= minimumDurability, so if durability < minimumDurability then we can reasonably assume that the elytra will soon be broken without replacement + return true; + } + NonNullList inv = ctx.player().inventory.mainInventory; + int qty = 0; + for (int i = 0; i < 36; i++) { + if (ElytraBehavior.isFireworks(inv.get(i))) { + qty += inv.get(i).getCount(); + } + } + if (qty <= Baritone.settings().elytraMinFireworksBeforeLanding.value) { + return true; + } + return false; + } + @Override public boolean isLoaded() { return true; diff --git a/src/main/java/baritone/process/elytra/ElytraBehavior.java b/src/main/java/baritone/process/elytra/ElytraBehavior.java index 9d497932b..709d22334 100644 --- a/src/main/java/baritone/process/elytra/ElytraBehavior.java +++ b/src/main/java/baritone/process/elytra/ElytraBehavior.java @@ -887,7 +887,7 @@ public final class ElytraBehavior implements Helper { } } - private static boolean isFireworks(final ItemStack itemStack) { + public static boolean isFireworks(final ItemStack itemStack) { if (itemStack.getItem() != Items.FIREWORKS) { return false; }