Compare commits
4 Commits
v1.2.18
...
pr/elytra/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3873aae710 | ||
|
|
19b66903d0 | ||
|
|
839ddaf85e | ||
|
|
b4780ca17e |
@@ -31,8 +31,7 @@
|
||||
<a href="https://github.com/cabaletta/baritone/commit/"><img src="https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg" alt="GitHub commits"/></a>
|
||||
<img src="https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg" alt="Code size"/>
|
||||
<img src="https://img.shields.io/github/repo-size/cabaletta/baritone.svg" alt="GitHub repo size"/>
|
||||
<img src="https://tokei.rs/b1/github/cabaletta/baritone?category=code&style=flat" alt="Lines of Code"/>
|
||||
<img src="https://img.shields.io/badge/Badges-36-blue.svg" alt="yes"/>
|
||||
<img src="https://tokei.rs/b1/github/cabaletta/baritone?category=code" alt="Lines of Code"/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@@ -46,8 +45,8 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="http://forthebadge.com/"><img src="https://web.archive.org/web/20230604002050/https://forthebadge.com/images/badges/built-with-swag.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://web.archive.org/web/20230604002050/https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/built-with-swag.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg" alt="forthebadge"/></a>
|
||||
</p>
|
||||
|
||||
A Minecraft pathfinder bot.
|
||||
@@ -69,8 +68,6 @@ Baritone is the pathfinding system used in [Impact](https://impactclient.net/) s
|
||||
| [1.19.4 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-forge-1.9.3.jar) | [1.19.4 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-fabric-1.9.3.jar) |
|
||||
| [1.20.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-forge-1.10.1.jar) | [1.20.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-fabric-1.10.1.jar) |
|
||||
|
||||
**Message for 2b2t players looking for 1.19/1.20 Baritone** Download it from right above ^. But also please check back in a few days for Baritone Elytra ([vid 1](https://youtu.be/4bGGPo8yiHo) [vid 2](https://www.youtube.com/watch?v=pUN9nmINe3I)), which will be ported to 1.19/1.20 soon! It will work on 2b2t with its anticheat, that was the whole point of Baritone Elytra (it's fully vanilla compatible). Also join [**the discord**](http://discord.gg/s6fRBAUpmr). Thanks!
|
||||
|
||||
**How to immediately get started:** Type `#goto 1000 500` in chat to go to x=1000 z=500. Type `#mine diamond_ore` to mine diamond ore. Type `#stop` to stop. For more, read [the usage page](USAGE.md) and/or watch this [tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa)
|
||||
|
||||
For other versions of Minecraft or more complicated situations or for development, see [Installation & setup](SETUP.md). Also consider just installing [Impact](https://impactclient.net/), which comes with Baritone and is easier to install than wrangling with version JSONs and zips. For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#6313 on Baritone which I recommend.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
group 'baritone'
|
||||
version '1.2.18'
|
||||
version '1.2.17'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
@@ -175,8 +175,8 @@ dependencies {
|
||||
transitive = false
|
||||
}
|
||||
launchAnnotationProcessor 'org.spongepowered:mixin:0.8.4-SNAPSHOT:processor'
|
||||
launchImplementation('dev.babbaj:nether-pathfinder:1.3.0')
|
||||
implementation 'dev.babbaj:nether-pathfinder:1.3.0'
|
||||
launchImplementation('dev.babbaj:nether-pathfinder:0.34')
|
||||
implementation 'dev.babbaj:nether-pathfinder:0.34'
|
||||
testImplementation 'junit:junit:4.12'
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api;
|
||||
|
||||
import baritone.api.behavior.IElytraBehavior;
|
||||
import baritone.api.behavior.ILookBehavior;
|
||||
import baritone.api.behavior.IPathingBehavior;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
@@ -40,6 +41,12 @@ public interface IBaritone {
|
||||
*/
|
||||
IPathingBehavior getPathingBehavior();
|
||||
|
||||
/**
|
||||
* @return The {@link IElytraBehavior} instance
|
||||
* @see IElytraBehavior
|
||||
*/
|
||||
IElytraBehavior getElytraBehavior();
|
||||
|
||||
/**
|
||||
* @return The {@link ILookBehavior} instance
|
||||
* @see ILookBehavior
|
||||
@@ -88,12 +95,6 @@ public interface IBaritone {
|
||||
*/
|
||||
IGetToBlockProcess getGetToBlockProcess();
|
||||
|
||||
/**
|
||||
* @return The {@link IElytraProcess} instance
|
||||
* @see IElytraProcess
|
||||
*/
|
||||
IElytraProcess getElytraProcess();
|
||||
|
||||
/**
|
||||
* @return The {@link IWorldProvider} instance
|
||||
* @see IWorldProvider
|
||||
|
||||
@@ -737,25 +737,16 @@ public final class Settings {
|
||||
public final Setting<Boolean> blockFreeLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Automatically elytra fly without having to force the client-sided rotations.
|
||||
* Automatically elytra fly without having to force the client-sided rotations. Requires {@link #freeLook}.
|
||||
*/
|
||||
public final Setting<Boolean> elytraFreeLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Forces the client-sided yaw rotation to an average of the last {@link #smoothLookTicks} of server-sided rotations.
|
||||
* Forces the client-sided rotations to an average of the last 10 ticks of server-sided rotations.
|
||||
* Requires {@link #freeLook}.
|
||||
*/
|
||||
public final Setting<Boolean> smoothLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Same as {@link #smoothLook} but for elytra flying.
|
||||
*/
|
||||
public final Setting<Boolean> elytraSmoothLook = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* The number of ticks to average across for {@link #smoothLook};
|
||||
*/
|
||||
public final Setting<Integer> smoothLookTicks = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* When true, the player will remain with its existing look direction as often as possible.
|
||||
* Although, in some cases this can get it stuck, hence this setting to disable that behavior.
|
||||
@@ -1356,7 +1347,7 @@ public final class Settings {
|
||||
/**
|
||||
* The minimum speed that the player can drop to (in blocks/tick) before a firework is automatically deployed.
|
||||
*/
|
||||
public final Setting<Double> elytraFireworkSpeed = new Setting<>(1.2);
|
||||
public final Setting<Double> elytraFireworkSpeed = new Setting<>(0.6);
|
||||
|
||||
/**
|
||||
* The delay after the player's position is set-back by the server that a firework may be automatically deployed.
|
||||
@@ -1375,23 +1366,23 @@ public final class Settings {
|
||||
/**
|
||||
* If enabled, avoids using fireworks when descending along the flight path.
|
||||
*/
|
||||
public final Setting<Boolean> elytraConserveFireworks = new Setting<>(false);
|
||||
public final Setting<Boolean> conserveFireworks = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Renders the raytraces that are performed by the elytra fly calculation.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderRaytraces = new Setting<>(false);
|
||||
public final Setting<Boolean> renderRaytraces = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Renders the raytraces that are used in the hitbox part of the elytra fly calculation.
|
||||
* Requires {@link #elytraRenderRaytraces}.
|
||||
* Requires {@link #renderRaytraces}.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderHitboxRaytraces = new Setting<>(false);
|
||||
public final Setting<Boolean> renderHitboxRaytraces = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Renders the best elytra flight path that was simulated each tick.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderSimulation = new Setting<>(true);
|
||||
public final Setting<Boolean> renderElytraSimulation = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Automatically path to and jump off of ledges to initiate elytra flight when grounded.
|
||||
@@ -1404,12 +1395,6 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Long> elytraNetherSeed = new Setting<>(146008555100680L);
|
||||
|
||||
/**
|
||||
* Whether nether-pathfinder should generate terrain based on {@link #elytraNetherSeed}.
|
||||
* If false all chunks that haven't been loaded are assumed to be air.
|
||||
*/
|
||||
public final Setting<Boolean> elytraPredictTerrain = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Automatically swap the current elytra with a new one when the durability gets too low
|
||||
*/
|
||||
@@ -1420,16 +1405,6 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Integer> elytraMinimumDurability = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* The minimum fireworks before landing early for safety
|
||||
*/
|
||||
public final Setting<Integer> elytraMinFireworksBeforeLanding = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* Automatically land when elytra is almost out of durability, or almost out of fireworks
|
||||
*/
|
||||
public final Setting<Boolean> elytraAllowEmergencyLand = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Time between culling far away chunks from the nether pathfinder chunk cache
|
||||
*/
|
||||
@@ -1440,16 +1415,6 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Integer> elytraCacheCullDistance = new Setting<>(5000);
|
||||
|
||||
/**
|
||||
* Should elytra consider nether brick a valid landing block
|
||||
*/
|
||||
public final Setting<Boolean> elytraAllowLandOnNetherFortress = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Has the user read and understood the elytra terms and conditions
|
||||
*/
|
||||
public final Setting<Boolean> elytraTermsAccepted = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* A map of lowercase setting field names to their respective setting
|
||||
*/
|
||||
|
||||
@@ -27,4 +27,10 @@ import baritone.api.event.listener.IGameEventListener;
|
||||
* @see IGameEventListener
|
||||
* @since 9/23/2018
|
||||
*/
|
||||
public interface IBehavior extends AbstractGameEventListener {}
|
||||
public interface IBehavior extends AbstractGameEventListener {
|
||||
|
||||
/**
|
||||
* Called after Baritone's initialization is complete
|
||||
*/
|
||||
default void onLoad() {}
|
||||
}
|
||||
|
||||
@@ -15,28 +15,32 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.process;
|
||||
package baritone.api.behavior;
|
||||
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public interface IElytraProcess extends IBaritoneProcess {
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public interface IElytraBehavior extends IBehavior {
|
||||
|
||||
/**
|
||||
* Marks the nether pathfinder context to be reset when it is safe to do so. Because this operation is not
|
||||
* immediate, a {@link CompletableFuture} is returned that will complete after the context has been reset.
|
||||
*
|
||||
* @return A {@link CompletableFuture} that is completed when the context is reset
|
||||
*/
|
||||
CompletableFuture<Void> resetContext();
|
||||
|
||||
void repackChunks();
|
||||
|
||||
/**
|
||||
* @return Where it is currently flying to, null if not active
|
||||
*/
|
||||
BlockPos currentDestination();
|
||||
|
||||
void pathTo(BlockPos destination);
|
||||
|
||||
void pathTo(Goal destination);
|
||||
void cancel();
|
||||
|
||||
/**
|
||||
* Resets the state of the process but will maintain the same destination and will try to keep flying
|
||||
* Returns {@code true} if the current {@link IElytraBehavior} is actively pathing.
|
||||
*/
|
||||
void resetState();
|
||||
boolean isActive();
|
||||
|
||||
/**
|
||||
* @return {@code true} if the native library loaded and elytra is actually usable
|
||||
@@ -22,7 +22,9 @@ import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
|
||||
@@ -27,8 +27,6 @@ import baritone.behavior.LookBehavior;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import net.minecraft.entity.player.PlayerCapabilities;
|
||||
import net.minecraft.item.ItemElytra;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@@ -125,19 +123,4 @@ public class MixinEntityPlayerSP {
|
||||
((LookBehavior) baritone.getLookBehavior()).pig();
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "onLivingUpdate",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/item/ItemElytra.isUsable(Lnet/minecraft/item/ItemStack;)Z"
|
||||
)
|
||||
)
|
||||
private boolean isElytraUsable(ItemStack stack) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((EntityPlayerSP) (Object) this);
|
||||
if (baritone != null && baritone.getPathingBehavior().isPathing()) {
|
||||
return false;
|
||||
}
|
||||
return ItemElytra.isUsable(stack);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,9 +21,9 @@ import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.behavior.IBehavior;
|
||||
import baritone.api.behavior.IElytraBehavior;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
@@ -66,7 +66,9 @@ public class Baritone implements IBaritone {
|
||||
|
||||
private final GameEventHandler gameEventHandler;
|
||||
|
||||
private final List<IBehavior> behaviors;
|
||||
private final PathingBehavior pathingBehavior;
|
||||
private final IElytraBehavior elytraBehavior;
|
||||
private final LookBehavior lookBehavior;
|
||||
private final InventoryBehavior inventoryBehavior;
|
||||
private final InputOverrideHandler inputOverrideHandler;
|
||||
@@ -79,7 +81,6 @@ public class Baritone implements IBaritone {
|
||||
private final ExploreProcess exploreProcess;
|
||||
private final FarmProcess farmProcess;
|
||||
private final InventoryPauserProcess inventoryPauserProcess;
|
||||
private final ElytraProcess elytraProcess;
|
||||
|
||||
private final PathingControlManager pathingControlManager;
|
||||
private final SelectionManager selectionManager;
|
||||
@@ -92,6 +93,7 @@ public class Baritone implements IBaritone {
|
||||
|
||||
Baritone(Minecraft mc) {
|
||||
this.mc = mc;
|
||||
this.behaviors = new ArrayList<>();
|
||||
this.gameEventHandler = new GameEventHandler(this);
|
||||
|
||||
this.directory = mc.gameDir.toPath().resolve("baritone");
|
||||
@@ -106,6 +108,7 @@ public class Baritone implements IBaritone {
|
||||
|
||||
{
|
||||
this.lookBehavior = this.registerBehavior(LookBehavior::new);
|
||||
this.elytraBehavior = this.registerBehavior(ElytraBehavior::create);
|
||||
this.pathingBehavior = this.registerBehavior(PathingBehavior::new);
|
||||
this.inventoryBehavior = this.registerBehavior(InventoryBehavior::new);
|
||||
this.inputOverrideHandler = this.registerBehavior(InputOverrideHandler::new);
|
||||
@@ -122,16 +125,18 @@ public class Baritone implements IBaritone {
|
||||
this.exploreProcess = this.registerProcess(ExploreProcess::new);
|
||||
this.farmProcess = this.registerProcess(FarmProcess::new);
|
||||
this.inventoryPauserProcess = this.registerProcess(InventoryPauserProcess::new);
|
||||
this.elytraProcess = this.registerProcess(ElytraProcess::create);
|
||||
this.registerProcess(BackfillProcess::new);
|
||||
}
|
||||
|
||||
this.worldProvider = new WorldProvider(this);
|
||||
this.selectionManager = new SelectionManager(this);
|
||||
this.commandManager = new CommandManager(this);
|
||||
|
||||
this.behaviors.forEach(IBehavior::onLoad);
|
||||
}
|
||||
|
||||
public void registerBehavior(IBehavior behavior) {
|
||||
this.behaviors.add(behavior);
|
||||
this.gameEventHandler.registerEventListener(behavior);
|
||||
}
|
||||
|
||||
@@ -236,8 +241,8 @@ public class Baritone implements IBaritone {
|
||||
}
|
||||
|
||||
@Override
|
||||
public IElytraProcess getElytraProcess() {
|
||||
return this.elytraProcess;
|
||||
public IElytraBehavior getElytraBehavior() {
|
||||
return this.elytraBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -15,25 +15,40 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.behavior.IElytraBehavior;
|
||||
import baritone.api.behavior.look.IAimProcessor;
|
||||
import baritone.api.behavior.look.ITickableAimProcessor;
|
||||
import baritone.api.event.events.*;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalBlock;
|
||||
import baritone.api.pathing.goals.GoalYLevel;
|
||||
import baritone.api.pathing.movement.IMovement;
|
||||
import baritone.api.pathing.path.IPathExecutor;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.*;
|
||||
import baritone.process.ElytraProcess;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.behavior.elytra.*;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.movements.MovementFall;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.IRenderer;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.accessor.IChunkProviderClient;
|
||||
import baritone.utils.accessor.IEntityFireworkRocket;
|
||||
import it.unimi.dsi.fastutil.floats.FloatArrayList;
|
||||
import it.unimi.dsi.fastutil.floats.FloatIterator;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||
import net.minecraft.block.material.Material;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.item.EntityFireworkRocket;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.inventory.ClickType;
|
||||
@@ -49,29 +64,29 @@ import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.UnaryOperator;
|
||||
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
import static baritone.utils.BaritoneMath.fastCeil;
|
||||
import static baritone.utils.BaritoneMath.fastFloor;
|
||||
|
||||
public final class ElytraBehavior implements Helper {
|
||||
private final Baritone baritone;
|
||||
private final IPlayerContext ctx;
|
||||
public final class ElytraBehavior extends Behavior implements IElytraBehavior, Helper {
|
||||
|
||||
// Render stuff
|
||||
private final List<Pair<Vec3d, Vec3d>> clearLines;
|
||||
private final List<Pair<Vec3d, Vec3d>> blockedLines;
|
||||
private List<Vec3d> simulationLine;
|
||||
private BlockPos aimPos;
|
||||
private List<BetterBlockPos> visiblePath;
|
||||
// Used exclusively for PathRenderer
|
||||
public List<Pair<Vec3d, Vec3d>> clearLines;
|
||||
public List<Pair<Vec3d, Vec3d>> blockedLines;
|
||||
public List<Vec3d> simulationLine;
|
||||
public BlockPos aimPos;
|
||||
public List<BetterBlockPos> visiblePath;
|
||||
|
||||
// :sunglasses:
|
||||
public final NetherPathfinderContext context;
|
||||
public final PathManager pathManager;
|
||||
private NetherPathfinderContext context;
|
||||
private CompletableFuture<Void> forceResetContext;
|
||||
private final PathManager pathManager;
|
||||
private final ElytraProcess process;
|
||||
|
||||
/**
|
||||
@@ -84,8 +99,6 @@ public final class ElytraBehavior implements Helper {
|
||||
*/
|
||||
private int remainingSetBackTicks;
|
||||
|
||||
public boolean landingMode;
|
||||
|
||||
/**
|
||||
* The most recent minimum number of firework boost ticks, equivalent to {@code 10 * (1 + Flight)}
|
||||
* <p>
|
||||
@@ -97,9 +110,8 @@ public final class ElytraBehavior implements Helper {
|
||||
private final int[] nextTickBoostCounter;
|
||||
|
||||
private BlockStateInterface bsi;
|
||||
private final BlockStateOctreeInterface boi;
|
||||
public final BlockPos destination;
|
||||
private final boolean appendDestination;
|
||||
private BlockStateOctreeInterface boi;
|
||||
private BlockPos destination;
|
||||
|
||||
private final ExecutorService solverExecutor;
|
||||
private Future<Solution> solver;
|
||||
@@ -112,25 +124,24 @@ public final class ElytraBehavior implements Helper {
|
||||
private int invTickCountdown = 0;
|
||||
private final Queue<Runnable> invTransactionQueue = new LinkedList<>();
|
||||
|
||||
public ElytraBehavior(Baritone baritone, ElytraProcess process, BlockPos destination, boolean appendDestination) {
|
||||
this.baritone = baritone;
|
||||
this.ctx = baritone.getPlayerContext();
|
||||
private ElytraBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
this.clearLines = new CopyOnWriteArrayList<>();
|
||||
this.blockedLines = new CopyOnWriteArrayList<>();
|
||||
this.pathManager = this.new PathManager();
|
||||
this.process = process;
|
||||
this.destination = destination;
|
||||
this.appendDestination = appendDestination;
|
||||
this.process = new ElytraProcess();
|
||||
this.solverExecutor = Executors.newSingleThreadExecutor();
|
||||
this.nextTickBoostCounter = new int[2];
|
||||
|
||||
this.context = new NetherPathfinderContext(Baritone.settings().elytraNetherSeed.value);
|
||||
this.boi = new BlockStateOctreeInterface(context);
|
||||
}
|
||||
|
||||
public final class PathManager {
|
||||
@Override
|
||||
public void onLoad() {
|
||||
baritone.getPathingControlManager().registerProcess(this.process);
|
||||
}
|
||||
|
||||
public NetherPath path;
|
||||
private final class PathManager {
|
||||
|
||||
private NetherPath path;
|
||||
private boolean completePath;
|
||||
private boolean recalculating;
|
||||
|
||||
@@ -194,7 +205,7 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
|
||||
this.recalculating = true;
|
||||
final List<BetterBlockPos> after = this.path.subList(upToIncl + 1, this.path.size());
|
||||
final List<BetterBlockPos> after = this.path.subList(upToIncl, this.path.size());
|
||||
final boolean complete = this.completePath;
|
||||
|
||||
return this.path0(ctx.playerFeet(), this.path.get(upToIncl), segment -> segment.append(after.stream(), complete))
|
||||
@@ -219,9 +230,8 @@ public final class ElytraBehavior implements Helper {
|
||||
this.recalculating = true;
|
||||
final List<BetterBlockPos> before = this.path.subList(0, afterIncl + 1);
|
||||
final long start = System.nanoTime();
|
||||
final BetterBlockPos pathStart = this.path.get(afterIncl);
|
||||
|
||||
this.path0(pathStart, ElytraBehavior.this.destination, segment -> segment.prepend(before.stream()))
|
||||
this.path0(this.path.get(afterIncl), ElytraBehavior.this.destination, segment -> segment.prepend(before.stream()))
|
||||
.thenRun(() -> {
|
||||
final int recompute = this.path.size() - before.size() - 1;
|
||||
final double distance = this.path.get(0).distanceTo(this.path.get(recompute));
|
||||
@@ -238,10 +248,6 @@ public final class ElytraBehavior implements Helper {
|
||||
final Throwable cause = ex.getCause();
|
||||
if (cause instanceof PathCalculationException) {
|
||||
logDirect("Failed to compute next segment");
|
||||
if (ctx.player().getDistanceSq(pathStart) < 16 * 16) {
|
||||
logDirect("Player is near the segment start, therefore repeating this calculation is pointless. Marking as complete");
|
||||
completePath = true;
|
||||
}
|
||||
} else {
|
||||
logUnhandledException(cause);
|
||||
}
|
||||
@@ -259,18 +265,7 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
|
||||
private void setPath(final UnpackedSegment segment) {
|
||||
List<BetterBlockPos> path = segment.collect();
|
||||
if (ElytraBehavior.this.appendDestination) {
|
||||
BlockPos dest = ElytraBehavior.this.destination;
|
||||
BlockPos last = !path.isEmpty() ? path.get(path.size() - 1) : null;
|
||||
if (last != null && ElytraBehavior.this.clearView(new Vec3d(dest), new Vec3d(last), false)) {
|
||||
path.add(new BetterBlockPos(dest));
|
||||
} else {
|
||||
logDirect("unable to land at " + ElytraBehavior.this.destination);
|
||||
process.landingSpotIsBad(new BetterBlockPos(ElytraBehavior.this.destination));
|
||||
}
|
||||
}
|
||||
this.path = new NetherPath(path);
|
||||
this.path = segment.collect();
|
||||
this.completePath = segment.isFinished();
|
||||
this.playerNear = 0;
|
||||
this.ticksNearUnchanged = 0;
|
||||
@@ -303,7 +298,6 @@ public final class ElytraBehavior implements Helper {
|
||||
while (rangeEndExcl < path.size() && ctx.world().isBlockLoaded(path.get(rangeEndExcl), false)) {
|
||||
rangeEndExcl++;
|
||||
}
|
||||
// rangeEndExcl now represents an index either not in the path, or just outside render distance
|
||||
if (rangeStartIncl >= rangeEndExcl) {
|
||||
// not loaded yet?
|
||||
return;
|
||||
@@ -314,7 +308,7 @@ public final class ElytraBehavior implements Helper {
|
||||
return; // previous iterations of this function SHOULD have fixed this by now :rage_cat:
|
||||
}
|
||||
|
||||
if (ElytraBehavior.this.process.state != ElytraProcess.State.LANDING && this.ticksNearUnchanged > 100) {
|
||||
if (ElytraBehavior.this.process.state != State.LANDING && this.ticksNearUnchanged > 100) {
|
||||
this.pathRecalcSegment(rangeEndExcl - 1)
|
||||
.thenRun(() -> {
|
||||
logDirect("Recalculating segment, no progress in last 100 ticks");
|
||||
@@ -323,11 +317,7 @@ public final class ElytraBehavior implements Helper {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean canSeeAny = false;
|
||||
for (int i = rangeStartIncl; i < rangeEndExcl - 1; i++) {
|
||||
if (ElytraBehavior.this.clearView(ctx.playerFeetAsVec(), this.path.getVec(i), false) || ElytraBehavior.this.clearView(ctx.playerHead(), this.path.getVec(i), false)) {
|
||||
canSeeAny = true;
|
||||
}
|
||||
if (!ElytraBehavior.this.clearView(this.path.getVec(i), this.path.getVec(i + 1), false)) {
|
||||
// obstacle. where do we return to pathing?
|
||||
// find the next valid segment
|
||||
@@ -348,9 +338,6 @@ public final class ElytraBehavior implements Helper {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!canSeeAny && rangeStartIncl < rangeEndExcl - 2 && process.state != ElytraProcess.State.GET_TO_JUMP) {
|
||||
this.pathRecalcSegment(rangeEndExcl - 1).thenRun(() -> logDirect("Recalculated segment since no path points were visible"));
|
||||
}
|
||||
}
|
||||
|
||||
private void attemptNextSegment() {
|
||||
@@ -393,12 +380,9 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
this.playerNear = index;
|
||||
}
|
||||
|
||||
public boolean isComplete() {
|
||||
return this.completePath;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRenderPass(RenderEvent event) {
|
||||
final Settings settings = Baritone.settings();
|
||||
if (this.visiblePath != null) {
|
||||
@@ -407,21 +391,21 @@ public final class ElytraBehavior implements Helper {
|
||||
if (this.aimPos != null) {
|
||||
PathRenderer.drawGoal(ctx.player(), new GoalBlock(this.aimPos), event.getPartialTicks(), Color.GREEN);
|
||||
}
|
||||
if (!this.clearLines.isEmpty() && settings.elytraRenderRaytraces.value) {
|
||||
if (!this.clearLines.isEmpty() && settings.renderRaytraces.value) {
|
||||
IRenderer.startLines(Color.GREEN, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value);
|
||||
for (Pair<Vec3d, Vec3d> line : this.clearLines) {
|
||||
IRenderer.emitLine(line.first(), line.second());
|
||||
}
|
||||
IRenderer.endLines(settings.renderPathIgnoreDepth.value);
|
||||
}
|
||||
if (!this.blockedLines.isEmpty() && Baritone.settings().elytraRenderRaytraces.value) {
|
||||
if (!this.blockedLines.isEmpty() && Baritone.settings().renderRaytraces.value) {
|
||||
IRenderer.startLines(Color.BLUE, settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value);
|
||||
for (Pair<Vec3d, Vec3d> line : this.blockedLines) {
|
||||
IRenderer.emitLine(line.first(), line.second());
|
||||
}
|
||||
IRenderer.endLines(settings.renderPathIgnoreDepth.value);
|
||||
}
|
||||
if (this.simulationLine != null && Baritone.settings().elytraRenderSimulation.value) {
|
||||
if (this.simulationLine != null && Baritone.settings().renderElytraSimulation.value) {
|
||||
IRenderer.startLines(new Color(0x36CCDC), settings.pathRenderLineWidthPixels.value, settings.renderPathIgnoreDepth.value);
|
||||
final Vec3d offset = new Vec3d(
|
||||
ctx.player().prevPosX + (ctx.player().posX - ctx.player().prevPosX) * event.getPartialTicks(),
|
||||
@@ -437,6 +421,25 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWorldEvent(WorldEvent event) {
|
||||
if (event.getWorld() != null) {
|
||||
if (event.getState() == EventState.PRE) {
|
||||
// Reset the context when it's safe to do so on the next game tick
|
||||
this.resetContext();
|
||||
}
|
||||
} else {
|
||||
if (event.getState() == EventState.POST) {
|
||||
// Exiting the world, just destroy and invalidate the context
|
||||
if (this.context != null) {
|
||||
this.context.destroy();
|
||||
this.context = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkEvent(ChunkEvent event) {
|
||||
if (event.isPostPopulate() && this.context != null) {
|
||||
final Chunk chunk = ctx.world().getChunk(event.getX(), event.getZ());
|
||||
@@ -444,10 +447,12 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockChange(BlockChangeEvent event) {
|
||||
this.context.queueBlockUpdate(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivePacket(PacketEvent event) {
|
||||
if (event.getPacket() instanceof SPacketPlayerPosLook) {
|
||||
ctx.minecraft().addScheduledTask(() -> {
|
||||
@@ -456,42 +461,64 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
}
|
||||
|
||||
public void pathTo() {
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
this.destination = destination;
|
||||
if (!Baritone.settings().elytraAutoJump.value || ctx.player().isElytraFlying()) {
|
||||
this.pathManager.pathToDestination();
|
||||
}
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@Override
|
||||
public void cancel() {
|
||||
this.destination = null;
|
||||
this.pathManager.clear();
|
||||
this.remainingFireworkTicks = 0;
|
||||
this.remainingSetBackTicks = 0;
|
||||
if (this.solver != null) {
|
||||
this.solver.cancel(true);
|
||||
this.solver = null;
|
||||
}
|
||||
this.solverExecutor.shutdown();
|
||||
try {
|
||||
while (!this.solverExecutor.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS)) {}
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
this.context.destroy();
|
||||
this.pendingSolution = null;
|
||||
Arrays.fill(this.nextTickBoostCounter, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> resetContext() {
|
||||
if (this.forceResetContext == null) {
|
||||
this.forceResetContext = new CompletableFuture<>();
|
||||
}
|
||||
return this.forceResetContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repackChunks() {
|
||||
((IChunkProviderClient) ctx.world().getChunkProvider()).loadedChunks().values()
|
||||
.forEach(this.context::queueForPacking);
|
||||
}
|
||||
|
||||
public void onTick() {
|
||||
synchronized (this.context.cullingLock) {
|
||||
this.onTick0();
|
||||
}
|
||||
final long now = System.currentTimeMillis();
|
||||
if ((now - this.timeLastCacheCull) / 1000 > Baritone.settings().elytraTimeBetweenCacheCullSecs.value) {
|
||||
this.context.queueCacheCulling(ctx.player().chunkCoordX, ctx.player().chunkCoordZ, Baritone.settings().elytraCacheCullDistance.value, this.boi);
|
||||
this.timeLastCacheCull = now;
|
||||
}
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return baritone.getPathingControlManager().mostRecentInControl()
|
||||
.filter(process -> this.process == process).isPresent();
|
||||
}
|
||||
|
||||
private void onTick0() {
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeToCancel() {
|
||||
return !this.isActive() || !(this.process.state == State.FLYING || this.process.state == State.START_FLYING);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(final TickEvent event) {
|
||||
if (event.getType() == TickEvent.Type.OUT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Fetch the previous solution, regardless of if it's going to be used
|
||||
this.pendingSolution = null;
|
||||
if (this.solver != null) {
|
||||
@@ -504,6 +531,23 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
}
|
||||
|
||||
// Setup/reset context
|
||||
final long netherSeed = Baritone.settings().elytraNetherSeed.value;
|
||||
if (this.context == null || this.context.getSeed() != netherSeed || this.forceResetContext != null) {
|
||||
if (this.context != null) {
|
||||
this.context.destroy();
|
||||
}
|
||||
this.context = new NetherPathfinderContext(netherSeed);
|
||||
if (this.forceResetContext != null) {
|
||||
this.forceResetContext.complete(null);
|
||||
this.forceResetContext = null;
|
||||
}
|
||||
if (this.context.getSeed() != netherSeed && this.isActive()) {
|
||||
logDirect("Nether seed changed, recalculating path");
|
||||
this.pathManager.pathToDestination();
|
||||
}
|
||||
}
|
||||
|
||||
tickInventoryTransactions();
|
||||
|
||||
// Certified mojang employee incident
|
||||
@@ -537,6 +581,7 @@ public final class ElytraBehavior implements Helper {
|
||||
|
||||
// ctx AND context???? :DDD
|
||||
this.bsi = new BlockStateInterface(ctx);
|
||||
this.boi = new BlockStateOctreeInterface(context);
|
||||
this.pathManager.tick();
|
||||
|
||||
final int playerNear = this.pathManager.getNear();
|
||||
@@ -544,12 +589,18 @@ public final class ElytraBehavior implements Helper {
|
||||
Math.max(playerNear - 30, 0),
|
||||
Math.min(playerNear + 100, path.size())
|
||||
);
|
||||
|
||||
final long now = System.currentTimeMillis();
|
||||
if ((now - this.timeLastCacheCull) / 1000 > Baritone.settings().elytraTimeBetweenCacheCullSecs.value) {
|
||||
this.context.queueCacheCulling(ctx.player().chunkCoordX, ctx.player().chunkCoordZ, Baritone.settings().elytraCacheCullDistance.value, this.boi);
|
||||
this.timeLastCacheCull = now;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by {@link baritone.process.ElytraProcess#onTick(boolean, boolean)} when the process is in control and the player is flying
|
||||
* Called by {@link ElytraProcess#onTick(boolean, boolean)} when the process is in control and the player is flying
|
||||
*/
|
||||
public void tick() {
|
||||
private void tick() {
|
||||
if (this.pathManager.getPath().isEmpty()) {
|
||||
return;
|
||||
}
|
||||
@@ -601,6 +652,7 @@ public final class ElytraBehavior implements Helper {
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTick(TickEvent event) {
|
||||
if (event.getType() == TickEvent.Type.IN && this.solveNextTick) {
|
||||
// We're at the end of the tick, the player's position likely updated and the closest path node could've
|
||||
@@ -615,7 +667,7 @@ public final class ElytraBehavior implements Helper {
|
||||
|
||||
private Solution solveAngles(final SolverContext context) {
|
||||
final NetherPath path = context.path;
|
||||
final int playerNear = landingMode ? path.size() - 1 : context.playerNear;
|
||||
final int playerNear = context.playerNear;
|
||||
final Vec3d start = context.start;
|
||||
Solution solution = null;
|
||||
|
||||
@@ -654,10 +706,7 @@ public final class ElytraBehavior implements Helper {
|
||||
|
||||
for (final Pair<Vec3d, Integer> candidate : candidates) {
|
||||
final Integer augment = candidate.second();
|
||||
Vec3d dest = candidate.first().add(0, augment, 0);
|
||||
if (landingMode) {
|
||||
dest = dest.add(0.5, 0.5, 0.5);
|
||||
}
|
||||
final Vec3d dest = candidate.first().add(0, augment, 0);
|
||||
|
||||
if (augment != 0) {
|
||||
if (i + lookahead >= path.size()) {
|
||||
@@ -705,10 +754,7 @@ public final class ElytraBehavior implements Helper {
|
||||
logDebug("waiting for elytraFireworkSetbackUseDelay: " + this.remainingSetBackTicks);
|
||||
return;
|
||||
}
|
||||
if (this.landingMode) {
|
||||
return;
|
||||
}
|
||||
final boolean useOnDescend = !Baritone.settings().elytraConserveFireworks.value || ctx.player().posY < goingTo.y + 5;
|
||||
final boolean useOnDescend = !Baritone.settings().conserveFireworks.value || ctx.player().posY < goingTo.y + 5;
|
||||
final double currentSpeed = new Vec3d(
|
||||
ctx.player().motionX,
|
||||
// ignore y component if we are BOTH below where we want to be AND descending
|
||||
@@ -742,26 +788,15 @@ public final class ElytraBehavior implements Helper {
|
||||
public final NetherPath path;
|
||||
public final int playerNear;
|
||||
public final Vec3d start;
|
||||
public final Vec3d motion;
|
||||
public final AxisAlignedBB boundingBox;
|
||||
public final boolean ignoreLava;
|
||||
public final FireworkBoost boost;
|
||||
public final IAimProcessor aimProcessor;
|
||||
|
||||
/**
|
||||
* Creates a new SolverContext using the current state of the path, player, and firework boost at the time of
|
||||
* construction.
|
||||
*
|
||||
* @param async Whether the computation is being done asynchronously at the end of a game tick.
|
||||
*/
|
||||
public SolverContext(boolean async) {
|
||||
this.path = ElytraBehavior.this.pathManager.getPath();
|
||||
this.playerNear = ElytraBehavior.this.pathManager.getNear();
|
||||
|
||||
this.start = ctx.playerFeetAsVec();
|
||||
this.motion = ctx.playerMotion();
|
||||
this.boundingBox = ctx.player().getEntityBoundingBox();
|
||||
this.ignoreLava = ctx.player().isInLava();
|
||||
this.start = ElytraBehavior.this.ctx.playerFeetAsVec();
|
||||
this.ignoreLava = ElytraBehavior.this.ctx.player().isInLava();
|
||||
|
||||
final Integer fireworkTicksExisted;
|
||||
if (async && ElytraBehavior.this.deployedFireworkLastTick) {
|
||||
@@ -793,8 +828,6 @@ public final class ElytraBehavior implements Helper {
|
||||
return this.path == other.path // Contents aren't modified, just compare by reference
|
||||
&& this.playerNear == other.playerNear
|
||||
&& Objects.equals(this.start, other.start)
|
||||
&& Objects.equals(this.motion, other.motion)
|
||||
&& Objects.equals(this.boundingBox, other.boundingBox)
|
||||
&& this.ignoreLava == other.ignoreLava
|
||||
&& Objects.equals(this.boost, other.boost);
|
||||
}
|
||||
@@ -806,11 +839,6 @@ public final class ElytraBehavior implements Helper {
|
||||
private final int minimumBoostTicks;
|
||||
private final int maximumBoostTicks;
|
||||
|
||||
/**
|
||||
* @param fireworkTicksExisted The ticksExisted of the attached firework entity, or {@code null} if no entity.
|
||||
* @param minimumBoostTicks The minimum number of boost ticks that the attached firework entity, if any, will
|
||||
* provide.
|
||||
*/
|
||||
public FireworkBoost(final Integer fireworkTicksExisted, final int minimumBoostTicks) {
|
||||
this.fireworkTicksExisted = fireworkTicksExisted;
|
||||
|
||||
@@ -887,7 +915,7 @@ public final class ElytraBehavior implements Helper {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isFireworks(final ItemStack itemStack) {
|
||||
private static boolean isFireworks(final ItemStack itemStack) {
|
||||
if (itemStack.getItem() != Items.FIREWORKS) {
|
||||
return false;
|
||||
}
|
||||
@@ -929,7 +957,7 @@ public final class ElytraBehavior implements Helper {
|
||||
return true;
|
||||
}
|
||||
|
||||
final AxisAlignedBB bb = context.boundingBox.grow(growAmount);
|
||||
final AxisAlignedBB bb = ctx.player().getEntityBoundingBox().grow(growAmount);
|
||||
|
||||
final double ox = dest.x - start.x;
|
||||
final double oy = dest.y - start.y;
|
||||
@@ -957,7 +985,7 @@ public final class ElytraBehavior implements Helper {
|
||||
};
|
||||
|
||||
// Use non-batching method without early failure
|
||||
if (Baritone.settings().elytraRenderHitboxRaytraces.value) {
|
||||
if (Baritone.settings().renderHitboxRaytraces.value) {
|
||||
boolean clear = true;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
final Vec3d s = new Vec3d(src[i * 3], src[i * 3 + 1], src[i * 3 + 2]);
|
||||
@@ -973,7 +1001,7 @@ public final class ElytraBehavior implements Helper {
|
||||
return this.context.raytrace(8, src, dst, NetherPathfinderContext.Visibility.ALL);
|
||||
}
|
||||
|
||||
public boolean clearView(Vec3d start, Vec3d dest, boolean ignoreLava) {
|
||||
private boolean clearView(Vec3d start, Vec3d dest, boolean ignoreLava) {
|
||||
final boolean clear;
|
||||
if (!ignoreLava) {
|
||||
// if start == dest then the cpp raytracer dies
|
||||
@@ -982,7 +1010,7 @@ public final class ElytraBehavior implements Helper {
|
||||
clear = ctx.world().rayTraceBlocks(start, dest, false, false, false) == null;
|
||||
}
|
||||
|
||||
if (Baritone.settings().elytraRenderRaytraces.value) {
|
||||
if (Baritone.settings().renderRaytraces.value) {
|
||||
(clear ? this.clearLines : this.blockedLines).add(new Pair<>(start, dest));
|
||||
}
|
||||
return clear;
|
||||
@@ -1091,21 +1119,19 @@ public final class ElytraBehavior implements Helper {
|
||||
while (pitches.hasNext()) {
|
||||
final float pitch = pitches.nextFloat();
|
||||
final List<Vec3d> displacement = this.simulate(
|
||||
context,
|
||||
context.aimProcessor.fork(),
|
||||
goalDelta,
|
||||
pitch,
|
||||
ticks,
|
||||
ticksBoosted,
|
||||
ticksBoostDelay
|
||||
ticksBoostDelay,
|
||||
context.ignoreLava
|
||||
);
|
||||
if (displacement == null) {
|
||||
continue;
|
||||
}
|
||||
final Vec3d last = displacement.get(displacement.size() - 1);
|
||||
double goodness = goalDirection.dotProduct(last.normalize());
|
||||
if (landingMode) {
|
||||
goodness = -goalDelta.subtract(last).length();
|
||||
}
|
||||
final double goodness = goalDirection.dotProduct(last.normalize());
|
||||
final PitchResult bestSoFar = bestResults.peek();
|
||||
if (bestSoFar == null || goodness > bestSoFar.dot) {
|
||||
bestResults.push(new PitchResult(pitch, goodness, displacement));
|
||||
@@ -1135,12 +1161,11 @@ public final class ElytraBehavior implements Helper {
|
||||
return null;
|
||||
}
|
||||
|
||||
private List<Vec3d> simulate(final SolverContext context, final Vec3d goalDelta, final float pitch, final int ticks,
|
||||
final int ticksBoosted, final int ticksBoostDelay) {
|
||||
final ITickableAimProcessor aimProcessor = context.aimProcessor.fork();
|
||||
private List<Vec3d> simulate(final ITickableAimProcessor aimProcessor, final Vec3d goalDelta, final float pitch,
|
||||
final int ticks, final int ticksBoosted, final int ticksBoostDelay, final boolean ignoreLava) {
|
||||
Vec3d delta = goalDelta;
|
||||
Vec3d motion = context.motion;
|
||||
AxisAlignedBB hitbox = context.boundingBox;
|
||||
Vec3d motion = ctx.playerMotion();
|
||||
AxisAlignedBB hitbox = ctx.player().getEntityBoundingBox();
|
||||
List<Vec3d> displacement = new ArrayList<>(ticks + 1);
|
||||
displacement.add(Vec3d.ZERO);
|
||||
int remainingTicksBoosted = ticksBoosted;
|
||||
@@ -1174,7 +1199,7 @@ public final class ElytraBehavior implements Helper {
|
||||
for (int x = xmin; x < xmax; x++) {
|
||||
for (int y = ymin; y < ymax; y++) {
|
||||
for (int z = zmin; z < zmax; z++) {
|
||||
if (!this.passable(x, y, z, context.ignoreLava)) {
|
||||
if (!this.passable(x, y, z, ignoreLava)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -1278,7 +1303,7 @@ public final class ElytraBehavior implements Helper {
|
||||
|
||||
ItemStack chest = ctx.player().inventory.armorInventory.get(2);
|
||||
if (chest.getItem() != Items.ELYTRA
|
||||
|| chest.getItem().getMaxDamage() - chest.getItemDamage() > Baritone.settings().elytraMinimumDurability.value) {
|
||||
|| chest.getItem().getMaxDamage() - chest.getItemDamage() > Baritone.settings().elytraMinimumDurability.value) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1356,4 +1381,210 @@ public final class ElytraBehavior implements Helper {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
private final class ElytraProcess implements IBaritoneProcess {
|
||||
|
||||
private State state;
|
||||
private Goal goal;
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return ElytraBehavior.this.destination != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
if (calcFailed) {
|
||||
onLostControl();
|
||||
logDirect("Failed to get to jump off spot, canceling");
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
final BetterBlockPos last = ElytraBehavior.this.pathManager.path.getLast();
|
||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < (5 * 5)) {
|
||||
this.state = State.LANDING;
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.LANDING) {
|
||||
final BetterBlockPos endPos = ElytraBehavior.this.pathManager.path.getLast();
|
||||
if (ctx.player().isElytraFlying() && endPos != null) {
|
||||
Vec3d from = ctx.player().getPositionVector();
|
||||
Vec3d to = new Vec3d(endPos.x, from.y, endPos.z);
|
||||
Rotation rotation = RotationUtils.calcRotationFromVec3d(from, to, ctx.playerRotations());
|
||||
baritone.getLookBehavior().updateTarget(rotation, false);
|
||||
} else {
|
||||
this.onLostControl();
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
} else if (ctx.player().isElytraFlying()) {
|
||||
this.state = State.FLYING;
|
||||
this.goal = null;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
ElytraBehavior.this.tick();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
if (this.state == State.FLYING || this.state == State.START_FLYING) {
|
||||
this.state = ctx.player().onGround && Baritone.settings().elytraAutoJump.value
|
||||
? State.LOCATE_JUMP
|
||||
: State.START_FLYING;
|
||||
}
|
||||
|
||||
if (this.state == State.LOCATE_JUMP) {
|
||||
if (this.goal == null) {
|
||||
this.goal = new GoalYLevel(31);
|
||||
}
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
if (executor != null && executor.getPath().getGoal() == this.goal) {
|
||||
final IMovement fall = executor.getPath().movements().stream()
|
||||
.filter(movement -> movement instanceof MovementFall)
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (fall != null) {
|
||||
final BetterBlockPos from = new BetterBlockPos(
|
||||
(fall.getSrc().x + fall.getDest().x) / 2,
|
||||
(fall.getSrc().y + fall.getDest().y) / 2,
|
||||
(fall.getSrc().z + fall.getDest().z) / 2
|
||||
);
|
||||
ElytraBehavior.this.pathManager.pathToDestination(from).whenComplete((result, ex) -> {
|
||||
if (!ElytraBehavior.this.clearView(new Vec3d(from), ElytraBehavior.this.pathManager.getPath().getVec(0), false)) {
|
||||
onLostControl();
|
||||
// TODO: Get to higher ground and then look again
|
||||
logDirect("Can't see start of path from jump spot, canceling");
|
||||
return;
|
||||
}
|
||||
if (ex == null) {
|
||||
this.state = State.GET_TO_JUMP;
|
||||
return;
|
||||
}
|
||||
onLostControl();
|
||||
});
|
||||
this.state = State.PAUSE;
|
||||
} else {
|
||||
onLostControl();
|
||||
logDirect("Jump off path didn't include a fall movement, canceling");
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
}
|
||||
return new PathingCommandContext(this.goal, PathingCommandType.SET_GOAL_AND_PAUSE, new WalkOffCalculationContext(baritone));
|
||||
}
|
||||
|
||||
// yucky
|
||||
if (this.state == State.PAUSE) {
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
if (this.state == State.GET_TO_JUMP) {
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
final boolean canStartFlying = ctx.player().fallDistance > 1.0f
|
||||
&& !isSafeToCancel
|
||||
&& executor != null
|
||||
&& executor.getPath().movements().get(executor.getPosition()) instanceof MovementFall;
|
||||
|
||||
if (canStartFlying) {
|
||||
this.state = State.START_FLYING;
|
||||
} else {
|
||||
return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.START_FLYING) {
|
||||
if (!isSafeToCancel) {
|
||||
// owned
|
||||
baritone.getPathingBehavior().secretInternalSegmentCancel();
|
||||
}
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
if (ctx.player().fallDistance > 1.0f) {
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, true);
|
||||
}
|
||||
}
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isTemporary() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
this.goal = null;
|
||||
this.state = State.START_FLYING;
|
||||
ElytraBehavior.this.cancel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double priority() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
final Supplier<String> status = () -> {
|
||||
switch (this.state) {
|
||||
case LOCATE_JUMP:
|
||||
return "Finding spot to jump off";
|
||||
case PAUSE:
|
||||
return "Waiting for elytra path";
|
||||
case GET_TO_JUMP:
|
||||
return "Walking to takeoff";
|
||||
case START_FLYING:
|
||||
return "Begin flying";
|
||||
case FLYING:
|
||||
return "Flying";
|
||||
case LANDING:
|
||||
return "Landing";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
};
|
||||
return "Elytra - " + status.get();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom calculation context which makes the player fall into lava
|
||||
*/
|
||||
private static final class WalkOffCalculationContext extends CalculationContext {
|
||||
|
||||
public WalkOffCalculationContext(IBaritone baritone) {
|
||||
super(baritone, true);
|
||||
this.allowFallIntoLava = true;
|
||||
this.minFallHeight = 8;
|
||||
this.maxFallHeightNoWater = 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double costOfPlacingAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double breakCostMultiplierAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double placeBucketCost() {
|
||||
return COST_INF;
|
||||
}
|
||||
}
|
||||
|
||||
private enum State {
|
||||
LOCATE_JUMP,
|
||||
VALIDATE_PATH,
|
||||
PAUSE,
|
||||
GET_TO_JUMP,
|
||||
START_FLYING,
|
||||
FLYING,
|
||||
LANDING
|
||||
}
|
||||
|
||||
public static <T extends Behavior & IElytraBehavior> T create(final Baritone baritone) {
|
||||
return (T) (NetherPathfinderContext.isSupported()
|
||||
? new ElytraBehavior(baritone)
|
||||
: new NullElytraBehavior(baritone));
|
||||
}
|
||||
}
|
||||
@@ -26,10 +26,9 @@ import baritone.api.event.events.*;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.behavior.look.ForkableRandom;
|
||||
import com.google.common.collect.EvictingQueue;
|
||||
import net.minecraft.network.play.client.CPacketPlayer;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
@@ -53,14 +52,12 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
|
||||
private final AimProcessor processor;
|
||||
|
||||
private final Deque<Float> smoothYawBuffer;
|
||||
private final Deque<Float> smoothPitchBuffer;
|
||||
private final EvictingQueue<Float> smoothYawBuffer;
|
||||
|
||||
public LookBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
this.processor = new AimProcessor(baritone.getPlayerContext());
|
||||
this.smoothYawBuffer = new ArrayDeque<>();
|
||||
this.smoothPitchBuffer = new ArrayDeque<>();
|
||||
this.smoothYawBuffer = EvictingQueue.create(10);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -91,8 +88,10 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
// Just return for PRE, we still want to set target to null on POST
|
||||
return;
|
||||
}
|
||||
if (this.target.mode == Target.Mode.SERVER) {
|
||||
this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch);
|
||||
}
|
||||
|
||||
this.prevRotation = new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch);
|
||||
final Rotation actual = this.processor.peekRotation(this.target.rotation);
|
||||
ctx.player().rotationYaw = actual.getYaw();
|
||||
ctx.player().rotationPitch = actual.getPitch();
|
||||
@@ -101,24 +100,15 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
case POST: {
|
||||
// Reset the player's rotations back to their original values
|
||||
if (this.prevRotation != null) {
|
||||
this.smoothYawBuffer.addLast(this.target.rotation.getYaw());
|
||||
while (this.smoothYawBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothYawBuffer.removeFirst();
|
||||
}
|
||||
this.smoothPitchBuffer.addLast(this.target.rotation.getPitch());
|
||||
while (this.smoothPitchBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothPitchBuffer.removeFirst();
|
||||
}
|
||||
if (this.target.mode == Target.Mode.SERVER) {
|
||||
if (Baritone.settings().smoothLook.value) {
|
||||
this.smoothYawBuffer.add(this.target.rotation.getYaw());
|
||||
ctx.player().rotationYaw = (float) this.smoothYawBuffer.stream()
|
||||
.mapToDouble(d -> d).average().orElseGet(this.prevRotation::getYaw);
|
||||
ctx.player().rotationPitch = this.prevRotation.getPitch();
|
||||
} else {
|
||||
ctx.player().rotationYaw = this.prevRotation.getYaw();
|
||||
ctx.player().rotationPitch = this.prevRotation.getPitch();
|
||||
} else if (ctx.player().isElytraFlying() ? Baritone.settings().elytraSmoothLook.value : Baritone.settings().smoothLook.value) {
|
||||
ctx.player().rotationYaw = (float) this.smoothYawBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getYaw());
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
ctx.player().rotationPitch = (float) this.smoothPitchBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getPitch());
|
||||
}
|
||||
}
|
||||
|
||||
this.prevRotation = null;
|
||||
}
|
||||
// The target is done being used for this game tick, so it can be invalidated
|
||||
@@ -325,22 +315,22 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
final Settings settings = Baritone.settings();
|
||||
final boolean antiCheat = settings.antiCheatCompatibility.value;
|
||||
final boolean blockFreeLook = settings.blockFreeLook.value;
|
||||
final boolean freeLook = settings.freeLook.value;
|
||||
|
||||
if (!freeLook) return CLIENT;
|
||||
if (!blockFreeLook && blockInteract) return CLIENT;
|
||||
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
// always need to set angles while flying
|
||||
return settings.elytraFreeLook.value ? SERVER : CLIENT;
|
||||
} else if (settings.freeLook.value) {
|
||||
// Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
|
||||
// rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
|
||||
// whatever the player is mousing over visually. Let's just settle for setting it silently.
|
||||
if (blockInteract) {
|
||||
return blockFreeLook ? SERVER : CLIENT;
|
||||
}
|
||||
return antiCheat ? SERVER : NONE;
|
||||
}
|
||||
|
||||
// all freeLook settings are disabled so set the angles
|
||||
return CLIENT;
|
||||
// Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
|
||||
// rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
|
||||
// whatever the player is mousing over visually. Let's just settle for setting it silently.
|
||||
if (antiCheat || blockInteract) return SERVER;
|
||||
|
||||
// Pathing regularly without antiCheatCompatibility, don't set the player rotation
|
||||
return NONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,6 @@ import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.process.ElytraProcess;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
@@ -311,7 +310,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
|
||||
public boolean isSafeToCancel() {
|
||||
if (current == null) {
|
||||
return !baritone.getElytraProcess().isActive() || baritone.getElytraProcess().isSafeToCancel();
|
||||
return !baritone.getElytraBehavior().isActive() || baritone.getElytraBehavior().isSafeToCancel();
|
||||
}
|
||||
return safeToCancel;
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
import dev.babbaj.pathfinder.NetherPathfinder;
|
||||
import dev.babbaj.pathfinder.Octree;
|
||||
@@ -27,7 +27,7 @@ public final class BlockStateOctreeInterface {
|
||||
|
||||
private final NetherPathfinderContext context;
|
||||
private final long contextPtr;
|
||||
transient long chunkPtr;
|
||||
volatile long chunkPtr;
|
||||
|
||||
// Guarantee that the first lookup will fetch the context by setting MAX_VALUE
|
||||
private int prevChunkX = Integer.MAX_VALUE;
|
||||
@@ -39,16 +39,19 @@ public final class BlockStateOctreeInterface {
|
||||
}
|
||||
|
||||
public boolean get0(final int x, final int y, final int z) {
|
||||
if ((y | (127 - y)) < 0) {
|
||||
if ((y | (128 - y)) < 0) {
|
||||
return false;
|
||||
}
|
||||
final int chunkX = x >> 4;
|
||||
final int chunkZ = z >> 4;
|
||||
if (this.chunkPtr == 0 | ((chunkX ^ this.prevChunkX) | (chunkZ ^ this.prevChunkZ)) != 0) {
|
||||
long pointer = this.chunkPtr;
|
||||
if (pointer == 0 | ((chunkX ^ this.prevChunkX) | (chunkZ ^ this.prevChunkZ)) != 0) {
|
||||
this.prevChunkX = chunkX;
|
||||
this.prevChunkZ = chunkZ;
|
||||
this.chunkPtr = NetherPathfinder.getOrCreateChunk(this.contextPtr, chunkX, chunkZ);
|
||||
synchronized (this.context.cacheLock) {
|
||||
this.chunkPtr = pointer = NetherPathfinder.getOrCreateChunk(this.contextPtr, chunkX, chunkZ);
|
||||
}
|
||||
}
|
||||
return Octree.getBlock(this.chunkPtr, x & 0xF, y & 0x7F, z & 0xF);
|
||||
return Octree.getBlock(pointer, x & 0xF, y & 0x7F, z & 0xF);
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.BlockChangeEvent;
|
||||
@@ -34,11 +34,13 @@ import net.minecraft.world.chunk.BlockStateContainer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -46,9 +48,7 @@ import java.util.concurrent.TimeUnit;
|
||||
public final class NetherPathfinderContext {
|
||||
|
||||
private static final IBlockState AIR_BLOCK_STATE = Blocks.AIR.getDefaultState();
|
||||
// This lock must be held while there are active pointers to chunks in java,
|
||||
// but we just hold it for the entire tick so we don't have to think much about it.
|
||||
public final Object cullingLock = new Object();
|
||||
public final Object cacheLock = new Object();
|
||||
|
||||
// Visible for access in BlockStateOctreeInterface
|
||||
final long context;
|
||||
@@ -58,12 +58,12 @@ public final class NetherPathfinderContext {
|
||||
public NetherPathfinderContext(long seed) {
|
||||
this.context = NetherPathfinder.newContext(seed);
|
||||
this.seed = seed;
|
||||
this.executor = Executors.newSingleThreadExecutor();
|
||||
this.executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new WorkQueue());
|
||||
}
|
||||
|
||||
public void queueCacheCulling(int chunkX, int chunkZ, int maxDistanceBlocks, BlockStateOctreeInterface boi) {
|
||||
this.executor.execute(() -> {
|
||||
synchronized (this.cullingLock) {
|
||||
synchronized (this.cacheLock) {
|
||||
boi.chunkPtr = 0L;
|
||||
NetherPathfinder.cullFarChunks(this.context, chunkX, chunkZ, maxDistanceBlocks);
|
||||
}
|
||||
@@ -104,9 +104,7 @@ public final class NetherPathfinderContext {
|
||||
src.getX(), src.getY(), src.getZ(),
|
||||
dst.getX(), dst.getY(), dst.getZ(),
|
||||
true,
|
||||
false,
|
||||
10000,
|
||||
!Baritone.settings().elytraPredictTerrain.value
|
||||
10000
|
||||
);
|
||||
if (segment == null) {
|
||||
throw new PathCalculationException("Path calculation failed");
|
||||
@@ -129,7 +127,7 @@ public final class NetherPathfinderContext {
|
||||
*/
|
||||
public boolean raytrace(final double startX, final double startY, final double startZ,
|
||||
final double endX, final double endY, final double endZ) {
|
||||
return NetherPathfinder.isVisible(this.context, NetherPathfinder.CACHE_MISS_SOLID, startX, startY, startZ, endX, endY, endZ);
|
||||
return NetherPathfinder.isVisible(this.context, true, startX, startY, startZ, endX, endY, endZ);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -141,24 +139,24 @@ public final class NetherPathfinderContext {
|
||||
* @return {@code true} if there is visibility between the points
|
||||
*/
|
||||
public boolean raytrace(final Vec3d start, final Vec3d end) {
|
||||
return NetherPathfinder.isVisible(this.context, NetherPathfinder.CACHE_MISS_SOLID, start.x, start.y, start.z, end.x, end.y, end.z);
|
||||
return NetherPathfinder.isVisible(this.context, true, start.x, start.y, start.z, end.x, end.y, end.z);
|
||||
}
|
||||
|
||||
public boolean raytrace(final int count, final double[] src, final double[] dst, final int visibility) {
|
||||
switch (visibility) {
|
||||
case Visibility.ALL:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, NetherPathfinder.CACHE_MISS_SOLID, count, src, dst, false) == -1;
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, false) == -1;
|
||||
case Visibility.NONE:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, NetherPathfinder.CACHE_MISS_SOLID, count, src, dst, true) == -1;
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, true) == -1;
|
||||
case Visibility.ANY:
|
||||
return NetherPathfinder.isVisibleMulti(this.context, NetherPathfinder.CACHE_MISS_SOLID, count, src, dst, true) != -1;
|
||||
return NetherPathfinder.isVisibleMulti(this.context, true, count, src, dst, true) != -1;
|
||||
default:
|
||||
throw new IllegalArgumentException("lol");
|
||||
}
|
||||
}
|
||||
|
||||
public void raytrace(final int count, final double[] src, final double[] dst, final boolean[] hitsOut, final double[] hitPosOut) {
|
||||
NetherPathfinder.raytrace(this.context, NetherPathfinder.CACHE_MISS_SOLID, count, src, dst, hitsOut, hitPosOut);
|
||||
NetherPathfinder.raytrace(this.context, true, count, src, dst, hitsOut, hitPosOut);
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
@@ -228,6 +226,221 @@ public final class NetherPathfinderContext {
|
||||
}
|
||||
}
|
||||
|
||||
private static final class WorkQueue extends TrollBlockingQueue<Runnable> {
|
||||
|
||||
private final LinkedList<Runnable> path;
|
||||
private final LinkedList<Runnable> chunk;
|
||||
|
||||
private final ReentrantLock takeLock = new ReentrantLock();
|
||||
private final ReentrantLock putLock = new ReentrantLock();
|
||||
private final Condition notEmpty = takeLock.newCondition();
|
||||
|
||||
public WorkQueue() {
|
||||
this.path = new LinkedList<>();
|
||||
this.chunk = new LinkedList<>();
|
||||
}
|
||||
|
||||
private void signalNotEmpty() {
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lock();
|
||||
try {
|
||||
this.notEmpty.signal();
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(@Nonnull Runnable runnable) {
|
||||
final ReentrantLock putLock = this.putLock;
|
||||
putLock.lock();
|
||||
try {
|
||||
if (runnable instanceof ForkJoinTask) {
|
||||
this.path.offer(runnable);
|
||||
} else {
|
||||
// Put new chunks at the head of the queue
|
||||
this.chunk.offerFirst(runnable);
|
||||
// Purge oldest chunks
|
||||
while (this.chunk.size() > Baritone.settings().chunkPackerQueueMaxSize.value) {
|
||||
this.chunk.removeLast();
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
putLock.unlock();
|
||||
}
|
||||
signalNotEmpty();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable take() throws InterruptedException {
|
||||
Runnable x;
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lockInterruptibly();
|
||||
try {
|
||||
while (size() == 0) {
|
||||
notEmpty.await();
|
||||
}
|
||||
x = dequeue();
|
||||
if (!isEmpty()) {
|
||||
notEmpty.signal();
|
||||
}
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Runnable poll(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
Runnable x;
|
||||
long nanos = unit.toNanos(timeout);
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lockInterruptibly();
|
||||
try {
|
||||
while (isEmpty()) {
|
||||
if (nanos <= 0)
|
||||
return null;
|
||||
nanos = notEmpty.awaitNanos(nanos);
|
||||
}
|
||||
x = dequeue();
|
||||
if (!isEmpty())
|
||||
notEmpty.signal();
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
return x;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
takeLock.lock();
|
||||
putLock.lock();
|
||||
try {
|
||||
return this.path.remove(o) || this.chunk.remove(o);
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drainTo(Collection<? super Runnable> c) {
|
||||
final ReentrantLock takeLock = this.takeLock;
|
||||
takeLock.lock();
|
||||
int n = size();
|
||||
try {
|
||||
if (!this.path.isEmpty()) {
|
||||
c.add(this.path.remove());
|
||||
}
|
||||
if (!this.chunk.isEmpty()) {
|
||||
c.add(this.chunk.remove());
|
||||
}
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
takeLock.lock();
|
||||
putLock.lock();
|
||||
try {
|
||||
return this.path.size() + this.chunk.size();
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return this.size() == 0;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public synchronized @Nonnull <T> T[] toArray(@Nonnull T[] a) {
|
||||
takeLock.lock();
|
||||
putLock.lock();
|
||||
try {
|
||||
return (T[]) Stream.concat(this.path.stream(), this.chunk.stream()).toArray(Runnable[]::new);
|
||||
} finally {
|
||||
takeLock.unlock();
|
||||
putLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private Runnable dequeue() {
|
||||
return !this.path.isEmpty() ? this.path.remove() : this.chunk.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("NullableProblems")
|
||||
private static class TrollBlockingQueue<T> extends AbstractQueue<T> implements BlockingQueue<T> {
|
||||
|
||||
@Override
|
||||
public Iterator<T> iterator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void put(T t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(T t, long timeout, TimeUnit unit) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T take() throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T poll(long timeout, TimeUnit unit) throws InterruptedException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int remainingCapacity() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drainTo(Collection<? super T> c) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int drainTo(Collection<? super T> c, int maxElements) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean offer(T t) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T poll() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T peek() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
public static final class Visibility {
|
||||
|
||||
public static final int ALL = 0;
|
||||
@@ -15,13 +15,11 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.api.behavior.IElytraBehavior;
|
||||
import baritone.behavior.Behavior;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -29,35 +27,30 @@ import java.util.concurrent.CompletableFuture;
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class NullElytraProcess extends BaritoneProcessHelper implements IElytraProcess {
|
||||
public final class NullElytraBehavior extends Behavior implements IElytraBehavior {
|
||||
|
||||
public NullElytraProcess(Baritone baritone) {
|
||||
public NullElytraBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> resetContext() {
|
||||
throw new UnsupportedOperationException("Called resetContext() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repackChunks() {
|
||||
throw new UnsupportedOperationException("Called repackChunks() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos currentDestination() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
throw new UnsupportedOperationException("Called pathTo() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(Goal destination) {
|
||||
throw new UnsupportedOperationException("Called pathTo() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
|
||||
public void cancel() {
|
||||
throw new UnsupportedOperationException("Called cancel() on NullElytraBehavior");
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,21 +58,6 @@ public final class NullElytraProcess extends BaritoneProcessHelper implements IE
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
throw new UnsupportedOperationException("Called onTick on NullElytraProcess");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
return "NullElytraProcess";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLoaded() {
|
||||
return false;
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -15,7 +15,7 @@
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process.elytra;
|
||||
package baritone.behavior.elytra;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import dev.babbaj.pathfinder.PathSegment;
|
||||
@@ -49,7 +49,7 @@ public final class UnpackedSegment {
|
||||
return new UnpackedSegment(Stream.concat(other, this.path), this.finished);
|
||||
}
|
||||
|
||||
public List<BetterBlockPos> collect() {
|
||||
public NetherPath collect() {
|
||||
final List<BetterBlockPos> path = this.path.collect(Collectors.toList());
|
||||
|
||||
// Remove backtracks
|
||||
@@ -67,7 +67,7 @@ public final class UnpackedSegment {
|
||||
}
|
||||
}
|
||||
|
||||
return path;
|
||||
return new NetherPath(path);
|
||||
}
|
||||
|
||||
public boolean isFinished() {
|
||||
@@ -23,7 +23,6 @@ import baritone.api.IBaritone;
|
||||
import baritone.api.cache.ICachedWorld;
|
||||
import baritone.api.cache.IWorldData;
|
||||
import baritone.api.utils.Helper;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
@@ -36,6 +35,7 @@ import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
@@ -69,7 +69,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
||||
* All chunk positions pending packing. This map will be updated in-place if a new update to the chunk occurs
|
||||
* while waiting in the queue for the packer thread to get to it.
|
||||
*/
|
||||
private final Map<ChunkPos, Chunk> toPackMap = CacheBuilder.newBuilder().softValues().<ChunkPos, Chunk>build().asMap();
|
||||
private final Map<ChunkPos, Chunk> toPackMap = new ConcurrentHashMap<>();
|
||||
|
||||
private final int dimension;
|
||||
|
||||
|
||||
@@ -17,29 +17,22 @@
|
||||
|
||||
package baritone.command.defaults;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.behavior.IElytraBehavior;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.exception.CommandInvalidStateException;
|
||||
import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalBlock;
|
||||
import baritone.api.pathing.goals.GoalXZ;
|
||||
import baritone.api.process.ICustomGoalProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
import net.minecraft.util.text.TextComponentString;
|
||||
import net.minecraft.util.text.TextFormatting;
|
||||
import net.minecraft.util.text.event.ClickEvent;
|
||||
import net.minecraft.util.text.event.HoverEvent;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
|
||||
|
||||
public class ElytraCommand extends Command {
|
||||
|
||||
public ElytraCommand(IBaritone baritone) {
|
||||
@@ -49,43 +42,51 @@ public class ElytraCommand extends Command {
|
||||
@Override
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
final ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess();
|
||||
final IElytraProcess elytra = baritone.getElytraProcess();
|
||||
if (args.hasExactlyOne() && args.peekString().equals("supported")) {
|
||||
logDirect(elytra.isLoaded() ? "yes" : unsupportedSystemMessage());
|
||||
return;
|
||||
}
|
||||
final IElytraBehavior elytra = baritone.getElytraBehavior();
|
||||
if (!elytra.isLoaded()) {
|
||||
throw new CommandInvalidStateException(unsupportedSystemMessage());
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osName = System.getProperty("os.name");
|
||||
throw new CommandInvalidStateException(String.format(
|
||||
"legacy architectures are not supported. your CPU is %s and your operating system is %s. " +
|
||||
"supported architectures are x86_64 or arm64, supported operating systems are windows, " +
|
||||
"linux, and mac",
|
||||
osArch, osName
|
||||
));
|
||||
}
|
||||
|
||||
if (!args.hasAny()) {
|
||||
if (Baritone.settings().elytraTermsAccepted.value) {
|
||||
if (detectOn2b2t()) {
|
||||
warn2b2t();
|
||||
}
|
||||
} else {
|
||||
gatekeep();
|
||||
}
|
||||
Goal iGoal = customGoalProcess.mostRecentGoal();
|
||||
if (iGoal == null) {
|
||||
throw new CommandInvalidStateException("No goal has been set");
|
||||
}
|
||||
if (ctx.player().dimension != -1) {
|
||||
throw new CommandInvalidStateException("Only works in the nether");
|
||||
final int x, y, z;
|
||||
if (iGoal instanceof GoalXZ) {
|
||||
GoalXZ goal = (GoalXZ) iGoal;
|
||||
x = goal.getX();
|
||||
y = 64;
|
||||
z = goal.getZ();
|
||||
} else if (iGoal instanceof GoalBlock) {
|
||||
GoalBlock goal = (GoalBlock) iGoal;
|
||||
x = goal.x;
|
||||
y = goal.y;
|
||||
z = goal.z;
|
||||
} else {
|
||||
throw new CommandInvalidStateException("The goal must be a GoalXZ or GoalBlock");
|
||||
}
|
||||
try {
|
||||
elytra.pathTo(iGoal);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new CommandInvalidStateException(ex.getMessage());
|
||||
if (y <= 0 || y >= 128) {
|
||||
throw new CommandInvalidStateException("The y of the goal is not between 0 and 128");
|
||||
}
|
||||
elytra.pathTo(new BlockPos(x, y, z));
|
||||
return;
|
||||
}
|
||||
|
||||
final String action = args.getString();
|
||||
switch (action) {
|
||||
case "reset": {
|
||||
elytra.resetState();
|
||||
logDirect("Reset state but still flying to same goal");
|
||||
elytra.resetContext().whenComplete((result, ex) -> {
|
||||
logDirect("Context reset, repacking chunks");
|
||||
elytra.repackChunks();
|
||||
});
|
||||
break;
|
||||
}
|
||||
case "repack": {
|
||||
@@ -99,99 +100,9 @@ public class ElytraCommand extends Command {
|
||||
}
|
||||
}
|
||||
|
||||
private void warn2b2t() {
|
||||
if (Baritone.settings().elytraPredictTerrain.value) {
|
||||
long seed = Baritone.settings().elytraNetherSeed.value;
|
||||
if (seed != NEW_2B2T_SEED && seed != OLD_2B2T_SEED) {
|
||||
logDirect(new TextComponentString("It looks like you're on 2b2t, but elytraNetherSeed is incorrect.")); // match color
|
||||
logDirect(suggest2b2tSeeds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private ITextComponent suggest2b2tSeeds() {
|
||||
TextComponentString clippy = new TextComponentString("");
|
||||
clippy.appendText("Within a few hundred blocks of spawn/axis/highways/etc, the terrain is too fragmented to be predictable. Baritone Elytra will still work, just with backtracking. ");
|
||||
clippy.appendText("However, once you get more than a few thousand blocks out, you should try ");
|
||||
TextComponentString olderSeed = new TextComponentString("the older seed (click here)");
|
||||
olderSeed.getStyle().setUnderlined(true).setBold(true).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraNetherSeed " + OLD_2B2T_SEED))).setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + OLD_2B2T_SEED));
|
||||
clippy.appendSibling(olderSeed);
|
||||
clippy.appendText(". Once you're further out into newer terrain generation (this includes everything up through 1.12), you should try ");
|
||||
TextComponentString newerSeed = new TextComponentString("the newer seed (click here)");
|
||||
newerSeed.getStyle().setUnderlined(true).setBold(true).setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraNetherSeed " + NEW_2B2T_SEED))).setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + NEW_2B2T_SEED));
|
||||
clippy.appendSibling(newerSeed);
|
||||
clippy.appendText(". Once you get into 1.19 terrain, the terrain becomes unpredictable again, due to custom non-vanilla generation, and you should set #elytraPredictTerrain to false. ");
|
||||
return clippy;
|
||||
}
|
||||
|
||||
private void gatekeep() {
|
||||
TextComponentString gatekeep = new TextComponentString("");
|
||||
gatekeep.appendText("To disable this message, enable the setting elytraTermsAccepted\n");
|
||||
gatekeep.appendText("Baritone Elytra is an experimental feature. It is only intended for long distance travel in the Nether using fireworks for vanilla boost. It will not work with any other mods (\"hacks\") for non-vanilla boost. ");
|
||||
TextComponentString gatekeep2 = new TextComponentString("If you want Baritone to attempt to take off from the ground for you, you can enable the elytraAutoJump setting (not advisable on laggy servers!). ");
|
||||
gatekeep2.getStyle().setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraAutoJump true")));
|
||||
gatekeep.appendSibling(gatekeep2);
|
||||
TextComponentString gatekeep3 = new TextComponentString("If you want Baritone to go slower, enable the elytraConserveFireworks setting and/or decrease the elytraFireworkSpeed setting. ");
|
||||
gatekeep3.getStyle().setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, new TextComponentString(Baritone.settings().prefix.value + "set elytraConserveFireworks true\n" + Baritone.settings().prefix.value + "set elytraFireworkSpeed 0.6\n(the 0.6 number is just an example, tweak to your liking)")));
|
||||
gatekeep.appendSibling(gatekeep3);
|
||||
TextComponentString gatekeep4 = new TextComponentString("Baritone Elytra ");
|
||||
TextComponentString red = new TextComponentString("wants to know the seed");
|
||||
red.getStyle().setColor(TextFormatting.RED).setUnderlined(true).setBold(true);
|
||||
gatekeep4.appendSibling(red);
|
||||
gatekeep4.appendText(" of the world you are in. If it doesn't have the correct seed, it will frequently backtrack. It uses the seed to generate terrain far beyond what you can see, since terrain obstacles in the Nether can be much larger than your render distance. ");
|
||||
gatekeep.appendSibling(gatekeep4);
|
||||
gatekeep.appendText("\n");
|
||||
if (detectOn2b2t()) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("It looks like you're on 2b2t. ");
|
||||
gatekeep5.appendSibling(suggest2b2tSeeds());
|
||||
if (!Baritone.settings().elytraPredictTerrain.value) {
|
||||
gatekeep5.appendText(Baritone.settings().prefix.value + "elytraPredictTerrain is currently disabled. ");
|
||||
} else {
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
gatekeep5.appendText("You are using the newer seed. ");
|
||||
} else if (Baritone.settings().elytraNetherSeed.value == OLD_2B2T_SEED) {
|
||||
gatekeep5.appendText("You are using the older seed. ");
|
||||
} else {
|
||||
gatekeep5.appendText("Defaulting to the newer seed. ");
|
||||
Baritone.settings().elytraNetherSeed.value = NEW_2B2T_SEED;
|
||||
}
|
||||
}
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
} else {
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone doesn't know the seed of your world. Set it with: " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere\n");
|
||||
gatekeep5.appendText("For the time being, elytraPredictTerrain is defaulting to false since the seed is unknown.");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
Baritone.settings().elytraPredictTerrain.value = false;
|
||||
} else {
|
||||
if (Baritone.settings().elytraPredictTerrain.value) {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone Elytra is predicting terrain assuming that " + Baritone.settings().elytraNetherSeed.value + " is the correct seed. Change that with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, or disable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain false");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
} else {
|
||||
TextComponentString gatekeep5 = new TextComponentString("Baritone Elytra is not predicting terrain. If you don't know the seed, this is the correct thing to do. If you do know the seed, input it with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, and then enable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain true");
|
||||
gatekeep.appendSibling(gatekeep5);
|
||||
}
|
||||
}
|
||||
}
|
||||
logDirect(gatekeep);
|
||||
}
|
||||
|
||||
private boolean detectOn2b2t() {
|
||||
if (true) return true;
|
||||
ServerData data = ctx.minecraft().getCurrentServerData();
|
||||
return data != null && data.serverIP.toLowerCase().contains("2b2t.org");
|
||||
}
|
||||
|
||||
private static final long OLD_2B2T_SEED = -4100785268875389365L;
|
||||
private static final long NEW_2B2T_SEED = 146008555100680L;
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
TabCompleteHelper helper = new TabCompleteHelper();
|
||||
if (args.hasExactlyOne()) {
|
||||
helper.append("reset", "repack", "supported");
|
||||
}
|
||||
return helper.filterPrefix(args.getString()).stream();
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -201,25 +112,6 @@ public class ElytraCommand extends Command {
|
||||
|
||||
@Override
|
||||
public List<String> getLongDesc() {
|
||||
return Arrays.asList(
|
||||
"The elytra command tells baritone to, in the nether, automatically fly to the current goal.",
|
||||
"",
|
||||
"Usage:",
|
||||
"> elytra - fly to the current goal",
|
||||
"> elytra reset - Resets the state of the process, but will try to keep flying to the same goal.",
|
||||
"> elytra repack - Queues all of the chunks in render distance to be given to the native library.",
|
||||
"> elytra supported - Tells you if baritone ships a native library that is compatible with your PC."
|
||||
);
|
||||
}
|
||||
|
||||
private static String unsupportedSystemMessage() {
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osName = System.getProperty("os.name");
|
||||
return String.format(
|
||||
"Legacy architectures are not supported. Your CPU is %s and your operating system is %s. " +
|
||||
"Supported architectures are 64 bit x86, and 64 bit ARM. Supported operating systems are Windows, " +
|
||||
"Linux, and Mac",
|
||||
osArch, osName
|
||||
);
|
||||
return Arrays.asList();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,7 @@ public class ExecutionControlCommands {
|
||||
paused[0] = false;
|
||||
}
|
||||
baritone.getPathingBehavior().cancelEverything();
|
||||
baritone.getElytraBehavior().cancel();
|
||||
logDirect("ok canceled");
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ public class ForceCancelCommand extends Command {
|
||||
IPathingBehavior pathingBehavior = baritone.getPathingBehavior();
|
||||
pathingBehavior.cancelEverything();
|
||||
pathingBehavior.forceCancel();
|
||||
baritone.getElytraBehavior().cancel();
|
||||
logDirect("ok force canceled");
|
||||
}
|
||||
|
||||
|
||||
@@ -56,9 +56,6 @@ public final class CustomGoalProcess extends BaritoneProcessHelper implements IC
|
||||
public void setGoal(Goal goal) {
|
||||
this.goal = goal;
|
||||
this.mostRecentGoal = goal;
|
||||
if (baritone.getElytraProcess().isActive()) {
|
||||
baritone.getElytraProcess().pathTo(goal);
|
||||
}
|
||||
if (this.state == State.NONE) {
|
||||
this.state = State.GOAL_SET;
|
||||
}
|
||||
|
||||
@@ -1,565 +0,0 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.process;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.event.events.*;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalBlock;
|
||||
import baritone.api.pathing.goals.GoalXZ;
|
||||
import baritone.api.pathing.goals.GoalYLevel;
|
||||
import baritone.api.pathing.movement.IMovement;
|
||||
import baritone.api.pathing.path.IPathExecutor;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.movements.MovementFall;
|
||||
import baritone.process.elytra.ElytraBehavior;
|
||||
import baritone.process.elytra.NetherPathfinderContext;
|
||||
import baritone.process.elytra.NullElytraProcess;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
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;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||
|
||||
public class ElytraProcess extends BaritoneProcessHelper implements IBaritoneProcess, IElytraProcess, AbstractGameEventListener {
|
||||
public State state;
|
||||
private boolean goingToLandingSpot;
|
||||
private BetterBlockPos landingSpot;
|
||||
private boolean reachedGoal; // this basically just prevents potential notification spam
|
||||
private Goal goal;
|
||||
private ElytraBehavior behavior;
|
||||
private boolean predictingTerrain;
|
||||
|
||||
private ElytraProcess(Baritone baritone) {
|
||||
super(baritone);
|
||||
baritone.getGameEventHandler().registerEventListener(this);
|
||||
}
|
||||
|
||||
public static <T extends IElytraProcess> T create(final Baritone baritone) {
|
||||
return (T) (NetherPathfinderContext.isSupported()
|
||||
? new ElytraProcess(baritone)
|
||||
: new NullElytraProcess(baritone));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActive() {
|
||||
return this.behavior != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetState() {
|
||||
BlockPos destination = this.currentDestination();
|
||||
this.onLostControl();
|
||||
if (destination != null) {
|
||||
this.pathTo(destination);
|
||||
this.repackChunks();
|
||||
}
|
||||
}
|
||||
|
||||
private static final String AUTO_JUMP_FAILURE_MSG = "Failed to compute a walking path to a spot to jump off from. Consider starting from a higher location, near an overhang. Or, you can disable elytraAutoJump and just manually begin gliding.";
|
||||
|
||||
@Override
|
||||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
final long seedSetting = Baritone.settings().elytraNetherSeed.value;
|
||||
if (seedSetting != this.behavior.context.getSeed()) {
|
||||
logDirect("Nether seed changed, recalculating path");
|
||||
this.resetState();
|
||||
}
|
||||
if (predictingTerrain != Baritone.settings().elytraPredictTerrain.value) {
|
||||
logDirect("elytraPredictTerrain setting changed, recalculating path");
|
||||
predictingTerrain = Baritone.settings().elytraPredictTerrain.value;
|
||||
this.resetState();
|
||||
}
|
||||
|
||||
this.behavior.onTick();
|
||||
|
||||
if (calcFailed) {
|
||||
onLostControl();
|
||||
logDirect(AUTO_JUMP_FAILURE_MSG);
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
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) || safetyLanding) && (!goingToLandingSpot || (safetyLanding && this.landingSpot == null))) {
|
||||
logDirect("Path complete, picking a nearby safe landing spot...");
|
||||
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);
|
||||
this.landingSpot = landingSpot;
|
||||
}
|
||||
this.goingToLandingSpot = true;
|
||||
}
|
||||
|
||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < 1) {
|
||||
if (Baritone.settings().notificationOnPathComplete.value && !reachedGoal) {
|
||||
logNotification("Pathing complete", false);
|
||||
}
|
||||
if (Baritone.settings().disconnectOnArrival.value && !reachedGoal) {
|
||||
// don't be active when the user logs back in
|
||||
this.onLostControl();
|
||||
ctx.world().sendQuittingDisconnectingPacket();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
reachedGoal = true;
|
||||
|
||||
// we are goingToLandingSpot and we are in the last node of the path
|
||||
if (this.goingToLandingSpot) {
|
||||
this.state = State.LANDING;
|
||||
logDirect("Above the landing spot, landing...");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.LANDING) {
|
||||
final BetterBlockPos endPos = this.landingSpot != null ? this.landingSpot : behavior.pathManager.path.getLast();
|
||||
if (ctx.player().isElytraFlying() && endPos != null) {
|
||||
Vec3d from = ctx.player().getPositionVector();
|
||||
Vec3d to = new Vec3d(((double) endPos.x) + 0.5, from.y, ((double) endPos.z) + 0.5);
|
||||
Rotation rotation = RotationUtils.calcRotationFromVec3d(from, to, ctx.playerRotations());
|
||||
baritone.getLookBehavior().updateTarget(new Rotation(rotation.getYaw(), 0), false); // this will be overwritten, probably, by behavior tick
|
||||
|
||||
if (ctx.player().posY < endPos.y - LANDING_COLUMN_HEIGHT) {
|
||||
logDirect("bad landing spot, trying again...");
|
||||
landingSpotIsBad(endPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
behavior.landingMode = this.state == State.LANDING;
|
||||
this.goal = null;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
behavior.tick();
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
} else if (this.state == State.LANDING) {
|
||||
if (Math.sqrt(ctx.player().motionX * ctx.player().motionX + ctx.player().motionZ * ctx.player().motionZ) > 0.001) {
|
||||
logDirect("Landed, but still moving, waiting for velocity to die down... ");
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.SNEAK, true);
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
logDirect("Done :)");
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
this.onLostControl();
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
if (this.state == State.FLYING || this.state == State.START_FLYING) {
|
||||
this.state = ctx.player().onGround && Baritone.settings().elytraAutoJump.value
|
||||
? State.LOCATE_JUMP
|
||||
: State.START_FLYING;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
if (executor != null && executor.getPath().getGoal() == this.goal) {
|
||||
final IMovement fall = executor.getPath().movements().stream()
|
||||
.filter(movement -> movement instanceof MovementFall)
|
||||
.findFirst().orElse(null);
|
||||
|
||||
if (fall != null) {
|
||||
final BetterBlockPos from = new BetterBlockPos(
|
||||
(fall.getSrc().x + fall.getDest().x) / 2,
|
||||
(fall.getSrc().y + fall.getDest().y) / 2,
|
||||
(fall.getSrc().z + fall.getDest().z) / 2
|
||||
);
|
||||
behavior.pathManager.pathToDestination(from).whenComplete((result, ex) -> {
|
||||
if (ex == null) {
|
||||
this.state = State.GET_TO_JUMP;
|
||||
return;
|
||||
}
|
||||
onLostControl();
|
||||
});
|
||||
this.state = State.PAUSE;
|
||||
} else {
|
||||
onLostControl();
|
||||
logDirect(AUTO_JUMP_FAILURE_MSG);
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
}
|
||||
return new PathingCommandContext(this.goal, PathingCommandType.SET_GOAL_AND_PAUSE, new WalkOffCalculationContext(baritone));
|
||||
}
|
||||
|
||||
// yucky
|
||||
if (this.state == State.PAUSE) {
|
||||
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
|
||||
}
|
||||
|
||||
if (this.state == State.GET_TO_JUMP) {
|
||||
final IPathExecutor executor = baritone.getPathingBehavior().getCurrent();
|
||||
final boolean canStartFlying = ctx.player().fallDistance > 1.0f
|
||||
&& !isSafeToCancel
|
||||
&& executor != null
|
||||
&& executor.getPath().movements().get(executor.getPosition()) instanceof MovementFall;
|
||||
|
||||
if (canStartFlying) {
|
||||
this.state = State.START_FLYING;
|
||||
} else {
|
||||
return new PathingCommand(null, PathingCommandType.SET_GOAL_AND_PATH);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state == State.START_FLYING) {
|
||||
if (!isSafeToCancel) {
|
||||
// owned
|
||||
baritone.getPathingBehavior().secretInternalSegmentCancel();
|
||||
}
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
if (ctx.player().fallDistance > 1.0f) {
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.JUMP, true);
|
||||
}
|
||||
}
|
||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
public void landingSpotIsBad(BetterBlockPos endPos) {
|
||||
badLandingSpots.add(endPos);
|
||||
goingToLandingSpot = false;
|
||||
this.landingSpot = null;
|
||||
this.state = State.FLYING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLostControl() {
|
||||
this.goal = null;
|
||||
this.goingToLandingSpot = false;
|
||||
this.landingSpot = null;
|
||||
this.reachedGoal = false;
|
||||
this.state = State.START_FLYING; // TODO: null state?
|
||||
destroyBehaviorAsync();
|
||||
}
|
||||
|
||||
private void destroyBehaviorAsync() {
|
||||
ElytraBehavior behavior = this.behavior;
|
||||
if (behavior != null) {
|
||||
this.behavior = null;
|
||||
Baritone.getExecutor().execute(behavior::destroy);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double priority() {
|
||||
return 0; // higher priority than CustomGoalProcess
|
||||
}
|
||||
|
||||
@Override
|
||||
public String displayName0() {
|
||||
return "Elytra - " + this.state.description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void repackChunks() {
|
||||
if (this.behavior != null) {
|
||||
this.behavior.repackChunks();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockPos currentDestination() {
|
||||
return this.behavior != null ? this.behavior.destination : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
this.pathTo0(destination, false);
|
||||
}
|
||||
|
||||
private void pathTo0(BlockPos destination, boolean appendDestination) {
|
||||
if (ctx.player() == null || ctx.player().dimension != -1) {
|
||||
return;
|
||||
}
|
||||
this.onLostControl();
|
||||
this.predictingTerrain = Baritone.settings().elytraPredictTerrain.value;
|
||||
this.behavior = new ElytraBehavior(this.baritone, this, destination, appendDestination);
|
||||
if (ctx.world() != null) {
|
||||
this.behavior.repackChunks();
|
||||
}
|
||||
this.behavior.pathTo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void pathTo(Goal iGoal) {
|
||||
final int x;
|
||||
final int y;
|
||||
final int z;
|
||||
if (iGoal instanceof GoalXZ) {
|
||||
GoalXZ goal = (GoalXZ) iGoal;
|
||||
x = goal.getX();
|
||||
y = 64;
|
||||
z = goal.getZ();
|
||||
} else if (iGoal instanceof GoalBlock) {
|
||||
GoalBlock goal = (GoalBlock) iGoal;
|
||||
x = goal.x;
|
||||
y = goal.y;
|
||||
z = goal.z;
|
||||
} else {
|
||||
throw new IllegalArgumentException("The goal must be a GoalXZ or GoalBlock");
|
||||
}
|
||||
if (y <= 0 || y >= 128) {
|
||||
throw new IllegalArgumentException("The y of the goal is not between 0 and 128");
|
||||
}
|
||||
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<ItemStack> 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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSafeToCancel() {
|
||||
return !this.isActive() || !(this.state == State.FLYING || this.state == State.START_FLYING);
|
||||
}
|
||||
|
||||
public enum State {
|
||||
LOCATE_JUMP("Finding spot to jump off"),
|
||||
PAUSE("Waiting for elytra path"),
|
||||
GET_TO_JUMP("Walking to takeoff"),
|
||||
START_FLYING("Begin flying"),
|
||||
FLYING("Flying"),
|
||||
LANDING("Landing");
|
||||
|
||||
public final String description;
|
||||
|
||||
State(String desc) {
|
||||
this.description = desc;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRenderPass(RenderEvent event) {
|
||||
if (this.behavior != null) this.behavior.onRenderPass(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWorldEvent(WorldEvent event) {
|
||||
if (event.getWorld() != null && event.getState() == EventState.POST) {
|
||||
// Exiting the world, just destroy
|
||||
destroyBehaviorAsync();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkEvent(ChunkEvent event) {
|
||||
if (this.behavior != null) this.behavior.onChunkEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBlockChange(BlockChangeEvent event) {
|
||||
if (this.behavior != null) this.behavior.onBlockChange(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivePacket(PacketEvent event) {
|
||||
if (this.behavior != null) this.behavior.onReceivePacket(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPostTick(TickEvent event) {
|
||||
IBaritoneProcess procThisTick = baritone.getPathingControlManager().mostRecentInControl().orElse(null);
|
||||
if (this.behavior != null && procThisTick == this) this.behavior.onPostTick(event);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom calculation context which makes the player fall into lava
|
||||
*/
|
||||
public static final class WalkOffCalculationContext extends CalculationContext {
|
||||
|
||||
public WalkOffCalculationContext(IBaritone baritone) {
|
||||
super(baritone, true);
|
||||
this.allowFallIntoLava = true;
|
||||
this.minFallHeight = 8;
|
||||
this.maxFallHeightNoWater = 10000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double costOfPlacingAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double breakCostMultiplierAt(int x, int y, int z, IBlockState current) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public double placeBucketCost() {
|
||||
return COST_INF;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isInBounds(BlockPos pos) {
|
||||
return pos.getY() >= 0 && pos.getY() < 128;
|
||||
}
|
||||
|
||||
private boolean isSafeBlock(Block block) {
|
||||
return block == Blocks.NETHERRACK || block == Blocks.GRAVEL || (block == Blocks.NETHER_BRICK && Baritone.settings().elytraAllowLandOnNetherFortress.value);
|
||||
}
|
||||
|
||||
private boolean isSafeBlock(BlockPos pos) {
|
||||
return isSafeBlock(ctx.world().getBlockState(pos).getBlock());
|
||||
}
|
||||
|
||||
private boolean isAtEdge(BlockPos pos) {
|
||||
return !isSafeBlock(pos.north())
|
||||
|| !isSafeBlock(pos.south())
|
||||
|| !isSafeBlock(pos.east())
|
||||
|| !isSafeBlock(pos.west())
|
||||
// corners
|
||||
|| !isSafeBlock(pos.north().west())
|
||||
|| !isSafeBlock(pos.north().east())
|
||||
|| !isSafeBlock(pos.south().west())
|
||||
|| !isSafeBlock(pos.south().east());
|
||||
}
|
||||
|
||||
private boolean isColumnAir(BlockPos landingSpot, int minHeight) {
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos(landingSpot);
|
||||
final int maxY = mut.getY() + minHeight;
|
||||
for (int y = mut.getY() + 1; y <= maxY; y++) {
|
||||
mut.setPos(mut.getX(), y, mut.getZ());
|
||||
if (!ctx.world().isAirBlock(mut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean hasAirBubble(BlockPos pos) {
|
||||
final int radius = 4; // Half of the full width, rounded down, as we're counting blocks in each direction from the center
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos();
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
mut.setPos(pos.getX() + x, pos.getY() + y, pos.getZ() + z);
|
||||
if (!ctx.world().isAirBlock(mut)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private BetterBlockPos checkLandingSpot(BlockPos pos, LongOpenHashSet checkedSpots) {
|
||||
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos(pos);
|
||||
while (mut.getY() >= 0) {
|
||||
if (checkedSpots.contains(mut.toLong())) {
|
||||
return null;
|
||||
}
|
||||
checkedSpots.add(mut.toLong());
|
||||
Block block = ctx.world().getBlockState(mut).getBlock();
|
||||
|
||||
if (isSafeBlock(block)) {
|
||||
if (!isAtEdge(mut)) {
|
||||
return new BetterBlockPos(mut);
|
||||
}
|
||||
return null;
|
||||
} else if (block != Blocks.AIR) {
|
||||
return null;
|
||||
}
|
||||
mut.setPos(mut.getX(), mut.getY() - 1, mut.getZ());
|
||||
}
|
||||
return null; // void
|
||||
}
|
||||
|
||||
private static final int LANDING_COLUMN_HEIGHT = 15;
|
||||
private Set<BetterBlockPos> badLandingSpots = new HashSet<>();
|
||||
|
||||
private BetterBlockPos findSafeLandingSpot(BetterBlockPos start) {
|
||||
Queue<BetterBlockPos> queue = new PriorityQueue<>(Comparator.<BetterBlockPos>comparingInt(pos -> (pos.x - start.x) * (pos.x - start.x) + (pos.z - start.z) * (pos.z - start.z)).thenComparingInt(pos -> -pos.y));
|
||||
Set<BetterBlockPos> visited = new HashSet<>();
|
||||
LongOpenHashSet checkedPositions = new LongOpenHashSet();
|
||||
queue.add(start);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
BetterBlockPos pos = queue.poll();
|
||||
if (ctx.world().isBlockLoaded(pos, false) && isInBounds(pos) && ctx.world().getBlockState(pos).getBlock() == Blocks.AIR) {
|
||||
BetterBlockPos actualLandingSpot = checkLandingSpot(pos, checkedPositions);
|
||||
if (actualLandingSpot != null && isColumnAir(actualLandingSpot, LANDING_COLUMN_HEIGHT) && hasAirBubble(actualLandingSpot.up(LANDING_COLUMN_HEIGHT)) && !badLandingSpots.contains(actualLandingSpot.up(LANDING_COLUMN_HEIGHT))) {
|
||||
return actualLandingSpot.up(LANDING_COLUMN_HEIGHT);
|
||||
}
|
||||
if (visited.add(pos.north())) queue.add(pos.north());
|
||||
if (visited.add(pos.east())) queue.add(pos.east());
|
||||
if (visited.add(pos.south())) queue.add(pos.south());
|
||||
if (visited.add(pos.west())) queue.add(pos.west());
|
||||
if (visited.add(pos.up())) queue.add(pos.up());
|
||||
if (visited.add(pos.down())) queue.add(pos.down());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,6 @@ public interface IRenderer {
|
||||
GlStateManager.glLineWidth(lineWidth);
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.depthMask(false);
|
||||
GlStateManager.disableLighting();
|
||||
|
||||
if (ignoreDepth) {
|
||||
GlStateManager.disableDepth();
|
||||
@@ -79,7 +78,6 @@ public interface IRenderer {
|
||||
GlStateManager.depthMask(true);
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.disableBlend();
|
||||
GlStateManager.enableLighting();
|
||||
}
|
||||
|
||||
static void emitAABB(AxisAlignedBB aabb) {
|
||||
|
||||
@@ -33,6 +33,7 @@ import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.math.AxisAlignedBB;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.MathHelper;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
@@ -40,6 +41,8 @@ import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/9/2018
|
||||
@@ -127,12 +130,12 @@ public final class PathRenderer implements IRenderer {
|
||||
int dirY = end.y - start.y;
|
||||
int dirZ = end.z - start.z;
|
||||
|
||||
while (next + 1 < positions.size() && (!fadeOut || next + 1 < fadeStart) &&
|
||||
/*while (next + 1 < positions.size() && (!fadeOut || next + 1 < fadeStart) &&
|
||||
(dirX == positions.get(next + 1).x - end.x &&
|
||||
dirY == positions.get(next + 1).y - end.y &&
|
||||
dirZ == positions.get(next + 1).z - end.z)) {
|
||||
end = positions.get(++next);
|
||||
}
|
||||
}*/
|
||||
|
||||
if (fadeOut) {
|
||||
float alpha;
|
||||
@@ -240,6 +243,8 @@ public final class PathRenderer implements IRenderer {
|
||||
GoalXZ goalPos = (GoalXZ) goal;
|
||||
|
||||
if (settings.renderGoalXZBeacon.value) {
|
||||
glPushAttrib(GL_LIGHTING_BIT);
|
||||
|
||||
textureManager.bindTexture(TileEntityBeaconRenderer.TEXTURE_BEACON_BEAM);
|
||||
|
||||
if (settings.renderGoalIgnoreDepth.value) {
|
||||
@@ -261,6 +266,8 @@ public final class PathRenderer implements IRenderer {
|
||||
if (settings.renderGoalIgnoreDepth.value) {
|
||||
GlStateManager.enableDepth();
|
||||
}
|
||||
|
||||
glPopAttrib();
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,8 +27,6 @@ import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.process.CustomGoalProcess;
|
||||
import baritone.process.ElytraProcess;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.*;
|
||||
@@ -111,6 +109,10 @@ public class PathingControlManager implements IPathingControlManager {
|
||||
p.cancelSegmentIfSafe();
|
||||
break;
|
||||
case FORCE_REVALIDATE_GOAL_AND_PATH:
|
||||
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
}
|
||||
break;
|
||||
case REVALIDATE_GOAL_AND_PATH:
|
||||
if (!p.isPathing() && !p.getInProgress().isPresent()) {
|
||||
p.secretInternalSetGoalAndPath(command);
|
||||
|
||||
Reference in New Issue
Block a user