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.utils.BaritoneProcessHelper;
|
||||
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.init.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
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 Goal goal;
|
||||
private LegacyElytraBehavior behavior;
|
||||
|
||||
|
@ -93,9 +102,9 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
return new PathingCommand(null, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
}
|
||||
|
||||
if (ctx.player().isElytraFlying()) {
|
||||
final BetterBlockPos last = behavior.pathManager.path.getLast();
|
||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < (5 * 5)) {
|
||||
if (ctx.player().isElytraFlying() && this.state != State.LANDING) {
|
||||
final BetterBlockPos last = this.behavior.pathManager.path.getLast();
|
||||
if (last != null && ctx.player().getDistanceSqToCenter(last) < 1) {
|
||||
if (Baritone.settings().notificationOnPathComplete.value) {
|
||||
logNotification("Pathing complete", false);
|
||||
}
|
||||
|
@ -105,15 +114,26 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
ctx.world().sendQuittingDisconnectingPacket();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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());
|
||||
baritone.getLookBehavior().updateTarget(rotation, false);
|
||||
} else {
|
||||
|
@ -208,6 +228,7 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
@Override
|
||||
public void onLostControl() {
|
||||
this.goal = null;
|
||||
this.goingToLandingSpot = false;
|
||||
this.state = State.START_FLYING; // TODO: null state?
|
||||
if (this.behavior != null) {
|
||||
this.behavior.destroy();
|
||||
|
@ -234,6 +255,7 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
|
||||
@Override
|
||||
public void pathTo(BlockPos destination) {
|
||||
this.onLostControl();
|
||||
this.behavior = new LegacyElytraBehavior(this.baritone, this, destination);
|
||||
if (ctx.world() != null) {
|
||||
this.behavior.repackChunks();
|
||||
|
@ -253,7 +275,6 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
|
||||
public enum State {
|
||||
LOCATE_JUMP("Finding spot to jump off"),
|
||||
VALIDATE_PATH("Validating path"),
|
||||
PAUSE("Waiting for elytra path"),
|
||||
GET_TO_JUMP("Walking to takeoff"),
|
||||
START_FLYING("Begin flying"),
|
||||
|
@ -329,4 +350,65 @@ public class ElytraProcess extends BaritoneProcessHelper implements IBaritonePro
|
|||
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