mirror of https://github.com/cabaletta/baritone
Merge pull request #4064 from babbaj/safe-landing
find safe landing spot for elytra
This commit is contained in:
commit
3ffacbf375
|
@ -41,15 +41,24 @@ import baritone.process.elytra.NetherPathfinderContext;
|
||||||
import baritone.process.elytra.NullElytraProcess;
|
import baritone.process.elytra.NullElytraProcess;
|
||||||
import baritone.utils.BaritoneProcessHelper;
|
import baritone.utils.BaritoneProcessHelper;
|
||||||
import baritone.utils.PathingCommandContext;
|
import baritone.utils.PathingCommandContext;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
|
import net.minecraft.block.Block;
|
||||||
|
import net.minecraft.block.material.Material;
|
||||||
import net.minecraft.block.state.IBlockState;
|
import net.minecraft.block.state.IBlockState;
|
||||||
|
import net.minecraft.init.Blocks;
|
||||||
import net.minecraft.util.math.BlockPos;
|
import net.minecraft.util.math.BlockPos;
|
||||||
import net.minecraft.util.math.Vec3d;
|
import net.minecraft.util.math.Vec3d;
|
||||||
|
import net.minecraft.util.math.Vec3i;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
|
||||||
|
|
||||||
public class ElytraProcess extends BaritoneProcessHelper implements IBaritoneProcess, IElytraProcess, AbstractGameEventListener {
|
public class ElytraProcess extends BaritoneProcessHelper implements IBaritoneProcess, IElytraProcess, AbstractGameEventListener {
|
||||||
|
|
||||||
public State state;
|
public State state;
|
||||||
|
private boolean goingToLandingSpot;
|
||||||
|
private BetterBlockPos landingSpot;
|
||||||
private Goal goal;
|
private Goal goal;
|
||||||
private LegacyElytraBehavior behavior;
|
private LegacyElytraBehavior behavior;
|
||||||
|
|
||||||
|
@ -93,9 +102,9 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx.player().isElytraFlying()) {
|
if (ctx.player().isElytraFlying() && this.state != State.LANDING) {
|
||||||
final BetterBlockPos last = behavior.pathManager.path.getLast();
|
final BetterBlockPos last = this.behavior.pathManager.path.getLast();
|
||||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < (5 * 5)) {
|
if (last != null && ctx.player().getDistanceSqToCenter(last) < 1) {
|
||||||
if (Baritone.settings().notificationOnPathComplete.value) {
|
if (Baritone.settings().notificationOnPathComplete.value) {
|
||||||
logNotification("Pathing complete", false);
|
logNotification("Pathing complete", false);
|
||||||
}
|
}
|
||||||
|
@ -105,15 +114,26 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
ctx.world().sendQuittingDisconnectingPacket();
|
ctx.world().sendQuittingDisconnectingPacket();
|
||||||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||||
}
|
}
|
||||||
|
if (!goingToLandingSpot) {
|
||||||
|
BetterBlockPos landingSpot = findSafeLandingSpot();
|
||||||
|
if (landingSpot != null) {
|
||||||
|
this.pathTo(landingSpot);
|
||||||
|
this.landingSpot = landingSpot;
|
||||||
|
this.goingToLandingSpot = true;
|
||||||
|
return this.onTick(calcFailed, isSafeToCancel);
|
||||||
|
}
|
||||||
|
// don't spam call findLandingSpot if it somehow fails (it's slow)
|
||||||
|
this.goingToLandingSpot = true;
|
||||||
|
}
|
||||||
this.state = State.LANDING;
|
this.state = State.LANDING;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.state == State.LANDING) {
|
if (this.state == State.LANDING) {
|
||||||
final BetterBlockPos endPos = behavior.pathManager.path.getLast();
|
final BetterBlockPos endPos = this.landingSpot != null ? this.landingSpot : behavior.pathManager.path.getLast();
|
||||||
if (ctx.player().isElytraFlying() && endPos != null) {
|
if (ctx.player().isElytraFlying() && endPos != null) {
|
||||||
Vec3d from = ctx.player().getPositionVector();
|
Vec3d from = ctx.player().getPositionVector();
|
||||||
Vec3d to = new Vec3d(endPos.x, from.y, endPos.z);
|
Vec3d to = new Vec3d(((double) endPos.x) + 0.5, from.y, ((double) endPos.z) + 0.5);
|
||||||
Rotation rotation = RotationUtils.calcRotationFromVec3d(from, to, ctx.playerRotations());
|
Rotation rotation = RotationUtils.calcRotationFromVec3d(from, to, ctx.playerRotations());
|
||||||
baritone.getLookBehavior().updateTarget(rotation, false);
|
baritone.getLookBehavior().updateTarget(rotation, false);
|
||||||
} else {
|
} else {
|
||||||
|
@ -208,6 +228,7 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
@Override
|
@Override
|
||||||
public void onLostControl() {
|
public void onLostControl() {
|
||||||
this.goal = null;
|
this.goal = null;
|
||||||
|
this.goingToLandingSpot = false;
|
||||||
this.state = State.START_FLYING; // TODO: null state?
|
this.state = State.START_FLYING; // TODO: null state?
|
||||||
if (this.behavior != null) {
|
if (this.behavior != null) {
|
||||||
this.behavior.destroy();
|
this.behavior.destroy();
|
||||||
|
@ -234,6 +255,7 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void pathTo(BlockPos destination) {
|
public void pathTo(BlockPos destination) {
|
||||||
|
this.onLostControl();
|
||||||
this.behavior = new LegacyElytraBehavior(this.baritone, this, destination);
|
this.behavior = new LegacyElytraBehavior(this.baritone, this, destination);
|
||||||
if (ctx.world() != null) {
|
if (ctx.world() != null) {
|
||||||
this.behavior.repackChunks();
|
this.behavior.repackChunks();
|
||||||
|
@ -253,7 +275,6 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
|
|
||||||
public enum State {
|
public enum State {
|
||||||
LOCATE_JUMP("Finding spot to jump off"),
|
LOCATE_JUMP("Finding spot to jump off"),
|
||||||
VALIDATE_PATH("Validating path"),
|
|
||||||
PAUSE("Waiting for elytra path"),
|
PAUSE("Waiting for elytra path"),
|
||||||
GET_TO_JUMP("Walking to takeoff"),
|
GET_TO_JUMP("Walking to takeoff"),
|
||||||
START_FLYING("Begin flying"),
|
START_FLYING("Begin flying"),
|
||||||
|
@ -329,4 +350,65 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
||||||
return COST_INF;
|
return COST_INF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isInBounds(BlockPos pos) {
|
||||||
|
return pos.getY() >= 0 && pos.getY() < 128;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isAtEdge(BlockPos pos) {
|
||||||
|
return ctx.world().isAirBlock(pos.north())
|
||||||
|
|| ctx.world().isAirBlock(pos.south())
|
||||||
|
|| ctx.world().isAirBlock(pos.east())
|
||||||
|
|| ctx.world().isAirBlock(pos.west())
|
||||||
|
// corners
|
||||||
|
|| ctx.world().isAirBlock(pos.north().west())
|
||||||
|
|| ctx.world().isAirBlock(pos.north().east())
|
||||||
|
|| ctx.world().isAirBlock(pos.south().west())
|
||||||
|
|| ctx.world().isAirBlock(pos.south().east());
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isSafeLandingSpot(BlockPos pos, LongOpenHashSet checkedSpots) {
|
||||||
|
BlockPos.MutableBlockPos mut = new BlockPos.MutableBlockPos(pos);
|
||||||
|
checkedSpots.add(mut.toLong());
|
||||||
|
while (mut.getY() >= 0) {
|
||||||
|
IBlockState state = ctx.world().getBlockState(mut);
|
||||||
|
Block block = state.getBlock();
|
||||||
|
|
||||||
|
if (block == Blocks.NETHERRACK || block == Blocks.GRAVEL || block == Blocks.NETHER_BRICK) {
|
||||||
|
return !isAtEdge(mut);
|
||||||
|
} else if (block != Blocks.AIR) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mut.setPos(mut.getX(), mut.getY() - 1, mut.getZ());
|
||||||
|
if (checkedSpots.contains(mut.toLong())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false; // void
|
||||||
|
}
|
||||||
|
|
||||||
|
private BetterBlockPos findSafeLandingSpot() {
|
||||||
|
final BetterBlockPos start = ctx.playerFeet();
|
||||||
|
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) && isInBounds(pos) && ctx.world().getBlockState(pos).getBlock() == Blocks.AIR) {
|
||||||
|
if (isSafeLandingSpot(pos, checkedPositions)) {
|
||||||
|
return pos;
|
||||||
|
}
|
||||||
|
checkedPositions.add(pos.toLong());
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue