Implement Leijurv's precomputed data idea
This commit is contained in:
parent
17a2aa42e9
commit
af1eb58bb8
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api;
|
||||
|
||||
import baritone.api.event.events.SettingChangedEvent;
|
||||
import baritone.api.utils.NotificationHelper;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.TypeUtils;
|
||||
@ -1302,6 +1303,11 @@ public final class Settings {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void set(T value) {
|
||||
this.value = value;
|
||||
BaritoneAPI.getProvider().getAllBaritones().forEach(iBaritone -> iBaritone.getGameEventHandler().onSettingChanged(new SettingChangedEvent(this)));
|
||||
}
|
||||
|
||||
public final String getName() {
|
||||
return name;
|
||||
}
|
||||
|
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.api.event.events;
|
||||
|
||||
import baritone.api.Settings;
|
||||
|
||||
public class SettingChangedEvent {
|
||||
|
||||
private final Settings.Setting<?> setting;
|
||||
|
||||
public SettingChangedEvent(Settings.Setting<?> setting) {
|
||||
this.setting = setting;
|
||||
}
|
||||
|
||||
public Settings.Setting<?> getSetting() {
|
||||
return setting;
|
||||
}
|
||||
}
|
@ -71,4 +71,7 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
||||
|
||||
@Override
|
||||
default void onPathEvent(PathEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onSettingChanged(SettingChangedEvent event) {}
|
||||
}
|
||||
|
@ -144,4 +144,11 @@ public interface IGameEventListener {
|
||||
* @param event The event
|
||||
*/
|
||||
void onPathEvent(PathEvent event);
|
||||
|
||||
/**
|
||||
* When the player changes a setting
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
void onSettingChanged(SettingChangedEvent event);
|
||||
}
|
||||
|
@ -176,7 +176,7 @@ public class SettingsUtil {
|
||||
/**
|
||||
* This should always be the same as whether the setting can be parsed from or serialized to a string
|
||||
*
|
||||
* @param the setting
|
||||
* @param setting The Setting
|
||||
* @return true if the setting can not be set or read by the user
|
||||
*/
|
||||
public static boolean javaOnlySetting(Settings.Setting setting) {
|
||||
@ -199,7 +199,7 @@ public class SettingsUtil {
|
||||
if (!intendedType.isInstance(parsed)) {
|
||||
throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass());
|
||||
}
|
||||
setting.value = parsed;
|
||||
setting.set(parsed);
|
||||
}
|
||||
|
||||
private interface ISettingParser<T> {
|
||||
|
@ -33,6 +33,7 @@ import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.pathing.precompute.PrecomputedData;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
@ -74,8 +75,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
|
||||
private final LinkedBlockingQueue<PathEvent> toDispatch = new LinkedBlockingQueue<>();
|
||||
|
||||
public PrecomputedData precomputedData;
|
||||
|
||||
public PathingBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
precomputedData = new PrecomputedData();
|
||||
}
|
||||
|
||||
private void queuePathEvent(PathEvent event) {
|
||||
@ -259,7 +263,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
if (command instanceof PathingCommandContext) {
|
||||
context = ((PathingCommandContext) command).desiredCalcContext;
|
||||
} else {
|
||||
context = new CalculationContext(baritone, true);
|
||||
context = new CalculationContext(baritone, true, precomputedData);
|
||||
}
|
||||
if (goal == null) {
|
||||
return false;
|
||||
@ -418,7 +422,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
*/
|
||||
public BetterBlockPos pathStart() { // TODO move to a helper or util class
|
||||
BetterBlockPos feet = ctx.playerFeet();
|
||||
if (!MovementHelper.canWalkOn(ctx, feet.down())) {
|
||||
if (!precomputedData.canWalkOn(ctx, feet.down())) {
|
||||
if (ctx.player().onGround) {
|
||||
double playerX = ctx.player().posX;
|
||||
double playerZ = ctx.player().posZ;
|
||||
@ -437,7 +441,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
// can't possibly be sneaking off of this one, we're too far away
|
||||
continue;
|
||||
}
|
||||
if (MovementHelper.canWalkOn(ctx, possibleSupport.down()) && MovementHelper.canWalkThrough(ctx, possibleSupport) && MovementHelper.canWalkThrough(ctx, possibleSupport.up())) {
|
||||
if (precomputedData.canWalkOn(ctx, possibleSupport.down()) && precomputedData.canWalkThrough(ctx, possibleSupport) && context.precomputedData.canWalkThrough(ctx, possibleSupport.up())) {
|
||||
// this is plausible
|
||||
//logDebug("Faking path start assuming player is standing off the edge of a block");
|
||||
return possibleSupport;
|
||||
@ -447,7 +451,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
} else {
|
||||
// !onGround
|
||||
// we're in the middle of a jump
|
||||
if (MovementHelper.canWalkOn(ctx, feet.down().down())) {
|
||||
if (precomputedData.canWalkOn(ctx, feet.down().down())) {
|
||||
//logDebug("Faking path start assuming player is midair and falling");
|
||||
return feet.down();
|
||||
}
|
||||
@ -456,6 +460,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
return feet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingChanged(SettingChangedEvent event) {
|
||||
this.precomputedData.refresh();
|
||||
}
|
||||
|
||||
/**
|
||||
* In a new thread, pathfind to target blockpos
|
||||
*
|
||||
|
@ -147,7 +147,8 @@ public class SetCommand extends Command {
|
||||
throw new CommandInvalidTypeException(args.consumed(), "a toggleable setting", "some other setting");
|
||||
}
|
||||
//noinspection unchecked
|
||||
((Settings.Setting<Boolean>) setting).value ^= true;
|
||||
Settings.Setting<Boolean> asBoolSetting = (Settings.Setting<Boolean>) setting;
|
||||
asBoolSetting.set(!asBoolSetting.value);
|
||||
logDirect(String.format(
|
||||
"Toggled setting %s to %s",
|
||||
setting.getName(),
|
||||
|
@ -156,6 +156,11 @@ public final class GameEventHandler implements IEventBus, Helper {
|
||||
listeners.forEach(l -> l.onPathEvent(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSettingChanged(SettingChangedEvent event) {
|
||||
listeners.forEach(l -> l.onSettingChanged(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void registerEventListener(IGameEventListener listener) {
|
||||
this.listeners.add(listener);
|
||||
|
@ -21,6 +21,7 @@ import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.pathing.movement.ActionCosts;
|
||||
import baritone.cache.WorldData;
|
||||
import baritone.pathing.precompute.PrecomputedData;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.ToolSet;
|
||||
import baritone.utils.pathing.BetterWorldBorder;
|
||||
@ -76,11 +77,14 @@ public class CalculationContext {
|
||||
public final double walkOnWaterOnePenalty;
|
||||
public final BetterWorldBorder worldBorder;
|
||||
|
||||
public final PrecomputedData precomputedData;
|
||||
|
||||
public CalculationContext(IBaritone baritone) {
|
||||
this(baritone, false);
|
||||
this(baritone, false, new PrecomputedData());
|
||||
}
|
||||
|
||||
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
|
||||
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread, PrecomputedData precomputedData) {
|
||||
this.precomputedData = precomputedData;
|
||||
this.safeForThreadedUse = forUseOnAnotherThread;
|
||||
this.baritone = baritone;
|
||||
EntityPlayerSP player = baritone.getPlayerContext().player();
|
||||
|
@ -88,6 +88,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z));
|
||||
}
|
||||
|
||||
// if changing something in this function remember to also change it in precomputed data
|
||||
static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
|
||||
Block block = state.getBlock();
|
||||
if (block == Blocks.AIR) { // early return for most common case
|
||||
@ -285,6 +286,8 @@ public interface MovementHelper extends ActionCosts, Helper {
|
||||
* through? Includes water because we know that we automatically jump on
|
||||
* water
|
||||
*
|
||||
* If changing something in this function remember to also change it in precomputed data
|
||||
*
|
||||
* @param bsi Block state provider
|
||||
* @param x The block's x position
|
||||
* @param y The block's y position
|
||||
|
@ -68,7 +68,7 @@ public class MovementAscend extends Movement {
|
||||
public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
|
||||
IBlockState toPlace = context.get(destX, y, destZ);
|
||||
double additionalPlacementCost = 0;
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, x, y, z, toPlace)) {
|
||||
additionalPlacementCost = context.costOfPlacingAt(destX, y, destZ, toPlace);
|
||||
if (additionalPlacementCost >= COST_INF) {
|
||||
return COST_INF;
|
||||
@ -94,7 +94,7 @@ public class MovementAscend extends Movement {
|
||||
}
|
||||
}
|
||||
IBlockState srcUp2 = context.get(x, y + 2, z); // used lower down anyway
|
||||
if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context.bsi, x, y + 1, z) || !(srcUp2.getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us
|
||||
if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (context.precomputedData.canWalkThrough(context.bsi, x, y + 1, z) || !(srcUp2.getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us
|
||||
// HOWEVER, we assume that we're standing in the start position
|
||||
// that means that src and src.up(1) are both air
|
||||
// maybe they aren't now, but they will be by the time this starts
|
||||
|
@ -101,7 +101,7 @@ public class MovementDescend extends Movement {
|
||||
//C, D, etc determine the length of the fall
|
||||
|
||||
IBlockState below = context.get(destX, y - 2, destZ);
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ, below)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, destX, y - 2, destZ, below)) {
|
||||
dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res);
|
||||
return;
|
||||
}
|
||||
@ -130,7 +130,7 @@ public class MovementDescend extends Movement {
|
||||
// and potentially replace the water we're going to fall into
|
||||
return false;
|
||||
}
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, y - 2, destZ, below)) {
|
||||
if (!context.precomputedData.canWalkThrough(context.bsi, destX, y - 2, destZ, below)) {
|
||||
return false;
|
||||
}
|
||||
double costSoFar = 0;
|
||||
@ -146,7 +146,7 @@ public class MovementDescend extends Movement {
|
||||
int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY
|
||||
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar;
|
||||
if (MovementHelper.isWater(ontoBlock.getBlock())) {
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
if (!context.precomputedData.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
return false;
|
||||
}
|
||||
if (context.assumeWalkOnWater) {
|
||||
@ -155,7 +155,7 @@ public class MovementDescend extends Movement {
|
||||
if (MovementHelper.isFlowing(destX, newY, destZ, ontoBlock, context.bsi)) {
|
||||
return false; // TODO flowing check required here?
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, newY - 1, destZ)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, destX, newY - 1, destZ)) {
|
||||
// we could punch right through the water into something else
|
||||
return false;
|
||||
}
|
||||
@ -174,10 +174,10 @@ public class MovementDescend extends Movement {
|
||||
effectiveStartHeight = newY;
|
||||
continue;
|
||||
}
|
||||
if (MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
if (context.precomputedData.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
continue;
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
return false;
|
||||
}
|
||||
if (MovementHelper.isBottomSlab(ontoBlock)) {
|
||||
|
@ -58,9 +58,9 @@ public class MovementDiagonal extends Movement {
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean safeToCancel(MovementState state) {
|
||||
protected boolean safeToCancel(MovementState state) { // TODO move this function to use precomputed data, not urgent as it only runs once a tick
|
||||
//too simple. backfill does not work after cornering with this
|
||||
//return MovementHelper.canWalkOn(ctx, ctx.playerFeet().down());
|
||||
//return context.precomputedData.canWalkOn(ctx, ctx.playerFeet().down());
|
||||
EntityPlayerSP player = ctx.player();
|
||||
double offset = 0.25;
|
||||
double x = player.posX;
|
||||
@ -110,24 +110,24 @@ public class MovementDiagonal extends Movement {
|
||||
}
|
||||
|
||||
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) {
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, y + 1, destZ)) {
|
||||
if (!context.precomputedData.canWalkThrough(context.bsi, destX, y + 1, destZ)) {
|
||||
return;
|
||||
}
|
||||
IBlockState destInto = context.get(destX, y, destZ);
|
||||
boolean ascend = false;
|
||||
IBlockState destWalkOn;
|
||||
boolean descend = false;
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, y, destZ, destInto)) {
|
||||
if (!context.precomputedData.canWalkThrough(context.bsi, destX, y, destZ, destInto)) {
|
||||
ascend = true;
|
||||
if (!context.allowDiagonalAscend || !MovementHelper.canWalkThrough(context.bsi, x, y + 2, z) || !MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi, destX, y + 2, destZ)) {
|
||||
if (!context.allowDiagonalAscend || !context.precomputedData.canWalkThrough(context.bsi, x, y + 2, z) || !context.precomputedData.canWalkOn(context.bsi, destX, y, destZ, destInto) || !context.precomputedData.canWalkThrough(context.bsi, destX, y + 2, destZ)) {
|
||||
return;
|
||||
}
|
||||
destWalkOn = destInto;
|
||||
} else {
|
||||
destWalkOn = context.get(destX, y - 1, destZ);
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
descend = true;
|
||||
if (!context.allowDiagonalDescend || !MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
if (!context.allowDiagonalDescend || !context.precomputedData.canWalkOn(context.bsi, destX, y - 2, destZ) || !context.precomputedData.canWalkThrough(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -169,17 +169,17 @@ public class MovementDiagonal extends Movement {
|
||||
IBlockState pb0 = context.get(x, y, destZ);
|
||||
IBlockState pb2 = context.get(destX, y, z);
|
||||
if (ascend) {
|
||||
boolean ATop = MovementHelper.canWalkThrough(context.bsi, x, y + 2, destZ);
|
||||
boolean AMid = MovementHelper.canWalkThrough(context.bsi, x, y + 1, destZ);
|
||||
boolean ALow = MovementHelper.canWalkThrough(context.bsi, x, y, destZ, pb0);
|
||||
boolean BTop = MovementHelper.canWalkThrough(context.bsi, destX, y + 2, z);
|
||||
boolean BMid = MovementHelper.canWalkThrough(context.bsi, destX, y + 1, z);
|
||||
boolean BLow = MovementHelper.canWalkThrough(context.bsi, destX, y, z, pb2);
|
||||
boolean ATop = context.precomputedData.canWalkThrough(context.bsi, x, y + 2, destZ);
|
||||
boolean AMid = context.precomputedData.canWalkThrough(context.bsi, x, y + 1, destZ);
|
||||
boolean ALow = context.precomputedData.canWalkThrough(context.bsi, x, y, destZ, pb0);
|
||||
boolean BTop = context.precomputedData.canWalkThrough(context.bsi, destX, y + 2, z);
|
||||
boolean BMid = context.precomputedData.canWalkThrough(context.bsi, destX, y + 1, z);
|
||||
boolean BLow = context.precomputedData.canWalkThrough(context.bsi, destX, y, z, pb2);
|
||||
if ((!(ATop && AMid && ALow) && !(BTop && BMid && BLow)) // no option
|
||||
|| MovementHelper.avoidWalkingInto(pb0.getBlock()) // bad
|
||||
|| MovementHelper.avoidWalkingInto(pb2.getBlock()) // bad
|
||||
|| (ATop && AMid && MovementHelper.canWalkOn(context.bsi, x, y, destZ, pb0)) // we could just ascend
|
||||
|| (BTop && BMid && MovementHelper.canWalkOn(context.bsi, destX, y, z, pb2)) // we could just ascend
|
||||
|| (ATop && AMid && context.precomputedData.canWalkOn(context.bsi, x, y, destZ, pb0)) // we could just ascend
|
||||
|| (BTop && BMid && context.precomputedData.canWalkOn(context.bsi, destX, y, z, pb2)) // we could just ascend
|
||||
|| (!ATop && AMid && ALow) // head bonk A
|
||||
|| (!BTop && BMid && BLow)) { // head bonk B
|
||||
return;
|
||||
|
@ -59,7 +59,7 @@ public class MovementDownward extends Movement {
|
||||
if (!context.allowDownward) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi, x, y - 2, z)) {
|
||||
if (!context.precomputedData.canWalkOn(context.bsi, x, y - 2, z)) {
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState down = context.get(x, y - 1, z);
|
||||
|
@ -74,7 +74,7 @@ public class MovementParkour extends Movement {
|
||||
return;
|
||||
}
|
||||
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff);
|
||||
if (MovementHelper.canWalkOn(context.bsi, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
|
||||
if (context.precomputedData.canWalkOn(context.bsi, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
|
||||
// second most common case -- we could just traverse not parkour
|
||||
return;
|
||||
}
|
||||
@ -122,7 +122,7 @@ public class MovementParkour extends Movement {
|
||||
// check for ascend landing position
|
||||
IBlockState destInto = context.bsi.get0(destX, y, destZ);
|
||||
if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.setPos(destX, y, destZ), destInto)) {
|
||||
if (i <= 3 && context.allowParkourAscend && context.canSprint && MovementHelper.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) {
|
||||
if (i <= 3 && context.allowParkourAscend && context.canSprint && context.precomputedData.canWalkOn(context.bsi, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) {
|
||||
res.x = destX;
|
||||
res.y = y + 1;
|
||||
res.z = destZ;
|
||||
@ -135,7 +135,7 @@ public class MovementParkour extends Movement {
|
||||
// check for flat landing position
|
||||
IBlockState landingOn = context.bsi.get0(destX, y - 1, destZ);
|
||||
// farmland needs to be canWalkOn otherwise farm can never work at all, but we want to specifically disallow ending a jump on farmland haha
|
||||
if (landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, landingOn)) {
|
||||
if (landingOn.getBlock() != Blocks.FARMLAND && context.precomputedData.canWalkOn(context.bsi, destX, y - 1, destZ, landingOn)) {
|
||||
if (checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) {
|
||||
res.x = destX;
|
||||
res.y = y;
|
||||
|
@ -120,7 +120,7 @@ public class MovementPillar extends Movement {
|
||||
}
|
||||
}
|
||||
// this is commented because it may have had a purpose, but it's very unclear what it was. it's from the minebot era.
|
||||
//if (!MovementHelper.canWalkOn(chkPos, check) || MovementHelper.canWalkThrough(chkPos, check)) {//if the block above where we want to break is not a full block, don't do it
|
||||
//if (!context.precomputedData.canWalkOn(chkPos, check) || context.precomputedData.canWalkThrough(chkPos, check)) {//if the block above where we want to break is not a full block, don't do it
|
||||
// TODO why does canWalkThrough mean this action is COST_INF?
|
||||
// BlockFalling makes sense, and !canWalkOn deals with weird cases like if it were lava
|
||||
// but I don't understand why canWalkThrough makes it impossible
|
||||
|
@ -72,7 +72,7 @@ public class MovementTraverse extends Movement {
|
||||
IBlockState pb1 = context.get(destX, y, destZ);
|
||||
IBlockState destOn = context.get(destX, y - 1, destZ);
|
||||
Block srcDown = context.getBlock(x, y - 1, z);
|
||||
if (MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
|
||||
if (context.precomputedData.canWalkOn(context.bsi, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
|
||||
double WC = WALK_ONE_BLOCK_COST;
|
||||
boolean water = false;
|
||||
if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) {
|
||||
|
@ -350,7 +350,7 @@ public class PathExecutor implements IPathExecutor, Helper {
|
||||
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false);
|
||||
|
||||
// first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint
|
||||
if (!new CalculationContext(behavior.baritone).canSprint) {
|
||||
if (!new CalculationContext(behavior.baritone, false, null).canSprint) {
|
||||
return false;
|
||||
}
|
||||
IMovement current = path.movements().get(pathPosition);
|
||||
|
237
src/main/java/baritone/pathing/precompute/PrecomputedData.java
Normal file
237
src/main/java/baritone/pathing/precompute/PrecomputedData.java
Normal file
@ -0,0 +1,237 @@
|
||||
/*
|
||||
* 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.pathing.precompute;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
import static baritone.pathing.movement.MovementHelper.isFlowing;
|
||||
import static baritone.pathing.movement.MovementHelper.isWater;
|
||||
|
||||
public class PrecomputedData { // TODO add isFullyPassable
|
||||
|
||||
PrecomputedDataForBlockState canWalkOn;
|
||||
PrecomputedDataForBlockState canWalkThrough;
|
||||
|
||||
public PrecomputedData() { // currently designed for this to be remade on setting change, however that could always be changed
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
canWalkOn = new PrecomputedDataForBlockState((state) -> { // this is just copied from the old MovementHelperFunction
|
||||
Block block = state.getBlock();
|
||||
if (block == Blocks.AIR || block == Blocks.MAGMA) {
|
||||
return Optional.of(false);
|
||||
}
|
||||
if (state.isBlockNormalCube()) {
|
||||
return Optional.of(true);
|
||||
}
|
||||
if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this
|
||||
return Optional.of(true);
|
||||
}
|
||||
if (block == Blocks.FARMLAND || block == Blocks.GRASS_PATH) {
|
||||
return Optional.of(true);
|
||||
}
|
||||
if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) {
|
||||
return Optional.of(true);
|
||||
}
|
||||
if (isWater(block)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (Baritone.settings().assumeWalkOnLava.value && MovementHelper.isLava(block)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (block instanceof BlockSlab) {
|
||||
if (!Baritone.settings().allowWalkOnBottomSlab.value) {
|
||||
if (((BlockSlab) block).isDouble()) {
|
||||
return Optional.of(true);
|
||||
}
|
||||
return Optional.of(state.getValue(BlockSlab.HALF) != BlockSlab.EnumBlockHalf.BOTTOM);
|
||||
}
|
||||
return Optional.of(true);
|
||||
}
|
||||
|
||||
return Optional.of(block instanceof BlockStairs);
|
||||
}, (bsi, x, y, z, blockState) -> { // This should just be water or lava, and could probably be made more efficient
|
||||
Block block = blockState.getBlock();
|
||||
if (isWater(block)) {
|
||||
// since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()"
|
||||
// BlockPos s that we'd just garbage collect immediately is actually noticeable. I don't even think it's a decrease in readability
|
||||
Block up = bsi.get0(x, y + 1, z).getBlock();
|
||||
if (up == Blocks.WATERLILY || up == Blocks.CARPET) {
|
||||
return true;
|
||||
}
|
||||
if (MovementHelper.isFlowing(x, y, z, blockState, bsi) || block == Blocks.FLOWING_WATER) {
|
||||
// the only scenario in which we can walk on flowing water is if it's under still water with jesus off
|
||||
return isWater(up) && !Baritone.settings().assumeWalkOnWater.value;
|
||||
}
|
||||
// if assumeWalkOnWater is on, we can only walk on water if there isn't water above it
|
||||
// if assumeWalkOnWater is off, we can only walk on water if there is water above it
|
||||
return isWater(up) ^ Baritone.settings().assumeWalkOnWater.value;
|
||||
}
|
||||
|
||||
if (Baritone.settings().assumeWalkOnLava.value && MovementHelper.isLava(block) && !MovementHelper.isFlowing(x, y, z, blockState, bsi)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // If we don't recognise it then we want to just return false to be safe.
|
||||
});
|
||||
|
||||
canWalkThrough = new PrecomputedDataForBlockState((blockState) -> {
|
||||
Block block = blockState.getBlock();
|
||||
|
||||
if (block == Blocks.AIR) {
|
||||
return Optional.of(true);
|
||||
}
|
||||
|
||||
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL || block == Blocks.COCOA || block instanceof BlockSkull || block instanceof BlockTrapDoor || block == Blocks.END_ROD) {
|
||||
return Optional.of(false);
|
||||
}
|
||||
|
||||
if (Baritone.settings().blocksToAvoid.value.contains(block)) {
|
||||
return Optional.of(false);
|
||||
}
|
||||
|
||||
if (block instanceof BlockDoor || block instanceof BlockFenceGate) {
|
||||
// Because there's no nice method in vanilla to check if a door is openable or not, we just have to assume
|
||||
// that anything that isn't an iron door isn't openable, ignoring that some doors introduced in mods can't
|
||||
// be opened by just interacting.
|
||||
return Optional.of(block != Blocks.IRON_DOOR);
|
||||
}
|
||||
|
||||
if (block == Blocks.CARPET) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (block instanceof BlockSnow) {
|
||||
if (blockState.getValue(BlockSnow.LAYERS) >= 3) {
|
||||
return Optional.of(false);
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
if (block instanceof BlockLiquid) {
|
||||
if (blockState.getValue(BlockLiquid.LEVEL) != 0) {
|
||||
return Optional.of(false);
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
if (block instanceof BlockCauldron) {
|
||||
return Optional.of(false);
|
||||
}
|
||||
|
||||
try { // A dodgy catch-all at the end, for most blocks with default behaviour this will work, however where blocks are special this will error out, and we can handle it when we have this information
|
||||
return Optional.of(block.isPassable(null, null));
|
||||
} catch (NullPointerException exception) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}, (bsi, x, y, z, blockState) -> {
|
||||
Block block = blockState.getBlock();
|
||||
|
||||
if (block == Blocks.CARPET) {
|
||||
return canWalkOn(bsi, x, y - 1, z);
|
||||
}
|
||||
|
||||
if (block instanceof BlockSnow) { // TODO see if this case is necessary, shouldn't it also check this somewhere else?
|
||||
return canWalkOn(bsi, x, y - 1, z);
|
||||
}
|
||||
|
||||
if (block instanceof BlockLiquid) {
|
||||
if (isFlowing(x, y, z, blockState, bsi)) {
|
||||
return false;
|
||||
}
|
||||
// Everything after this point has to be a special case as it relies on the water not being flowing, which means a special case is needed.
|
||||
if (Baritone.settings().assumeWalkOnWater.value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
IBlockState up = bsi.get0(x, y + 1, z);
|
||||
if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
|
||||
return false;
|
||||
}
|
||||
return block == Blocks.WATER || block == Blocks.FLOWING_WATER;
|
||||
}
|
||||
|
||||
return block.isPassable(bsi.access, bsi.isPassableBlockPos.setPos(x, y, z));
|
||||
});
|
||||
|
||||
long endTime = System.nanoTime();
|
||||
|
||||
System.out.println(endTime - startTime);
|
||||
Thread.dumpStack();
|
||||
}
|
||||
|
||||
public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
|
||||
return canWalkOn.get(bsi, x, y, z, state);
|
||||
}
|
||||
|
||||
public boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos, IBlockState state) {
|
||||
return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z, state);
|
||||
}
|
||||
|
||||
public boolean canWalkOn(IPlayerContext ctx, BlockPos pos) {
|
||||
return canWalkOn(new BlockStateInterface(ctx), pos.getX(), pos.getY(), pos.getZ());
|
||||
}
|
||||
|
||||
public boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos) {
|
||||
return canWalkOn(new BlockStateInterface(ctx), pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z) {
|
||||
return canWalkOn(bsi, x, y, z, bsi.get0(x, y, z));
|
||||
}
|
||||
|
||||
public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean canWalkThrough(IPlayerContext ctx, BetterBlockPos pos) {
|
||||
return canWalkThrough(new BlockStateInterface(ctx), pos.x, pos.y, pos.z);
|
||||
}
|
||||
|
||||
public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z) {
|
||||
return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z));
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the precomputed data, for use when settings have changed etc.
|
||||
*/
|
||||
public void refresh() {
|
||||
long startTime = System.nanoTime();
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
canWalkThrough.refresh();
|
||||
canWalkOn.refresh();
|
||||
}
|
||||
|
||||
long endTime = System.nanoTime();
|
||||
|
||||
System.out.println(endTime - startTime);
|
||||
}
|
||||
}
|
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.pathing.precompute;
|
||||
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.world.IBlockAccess;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class PrecomputedDataForBlockState {
|
||||
boolean[] dataPerBlockState = new boolean[Block.BLOCK_STATE_IDS.size()]; // Has to be of type boolean due to otherwise it has a generic type
|
||||
boolean[] specialCases = new boolean[Block.BLOCK_STATE_IDS.size()]; // We can also be certain that size will return the highest as it fills in all positions with null until we get to the highest block state
|
||||
|
||||
private final SpecialCaseFunction specialCaseHandler;
|
||||
private final Function<IBlockState, Optional<Boolean>> precomputer;
|
||||
|
||||
public PrecomputedDataForBlockState(Function<IBlockState, Optional<Boolean>> precomputer, SpecialCaseFunction specialCaseHandler) {
|
||||
this.specialCaseHandler = specialCaseHandler;
|
||||
this.precomputer = precomputer;
|
||||
|
||||
this.refresh();
|
||||
}
|
||||
|
||||
public void refresh() {
|
||||
for (IBlockState state : Block.BLOCK_STATE_IDS) { // state should never be null
|
||||
Optional<Boolean> applied = precomputer.apply(state);
|
||||
|
||||
int id = Block.BLOCK_STATE_IDS.get(state);
|
||||
|
||||
if (applied.isPresent()) {
|
||||
dataPerBlockState[id] = applied.get();
|
||||
specialCases[id] = false;
|
||||
} else {
|
||||
dataPerBlockState[id] = false;
|
||||
specialCases[id] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean get(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
|
||||
int id = Block.BLOCK_STATE_IDS.get(state);
|
||||
if (specialCases[id]) {
|
||||
return specialCaseHandler.apply(bsi, x, y, z, state);
|
||||
} else {
|
||||
return dataPerBlockState[id];
|
||||
}
|
||||
}
|
||||
|
||||
interface SpecialCaseFunction {
|
||||
public boolean apply(BlockStateInterface bsi, int x, int y, int z, IBlockState blockState);
|
||||
}
|
||||
}
|
@ -38,6 +38,7 @@ import baritone.api.utils.input.Input;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.Movement;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.precompute.PrecomputedData;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
@ -893,7 +894,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
|
||||
private final int originZ;
|
||||
|
||||
public BuilderCalculationContext() {
|
||||
super(BuilderProcess.this.baritone, true); // wew lad
|
||||
super(BuilderProcess.this.baritone, true, new PrecomputedData()); // wew lad
|
||||
this.placeable = approxPlaceable(9);
|
||||
this.schematic = BuilderProcess.this.schematic;
|
||||
this.originX = origin.getX();
|
||||
|
@ -158,7 +158,7 @@ public final class GetToBlockProcess extends BaritoneProcessHelper implements IG
|
||||
public class GetToBlockCalculationContext extends CalculationContext {
|
||||
|
||||
public GetToBlockCalculationContext(boolean forUseOnAnotherThread) {
|
||||
super(GetToBlockProcess.super.baritone, forUseOnAnotherThread);
|
||||
super(GetToBlockProcess.super.baritone, forUseOnAnotherThread, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -111,7 +111,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
||||
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value;
|
||||
List<BlockPos> curr = new ArrayList<>(knownOreLocations);
|
||||
if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain
|
||||
CalculationContext context = new CalculationContext(baritone, true);
|
||||
CalculationContext context = new CalculationContext(baritone, true, null); // Precomputed data should never be used on this calculation context
|
||||
Baritone.getExecutor().execute(() -> rescan(curr, context));
|
||||
}
|
||||
if (Baritone.settings().legitMine.value) {
|
||||
|
Loading…
Reference in New Issue
Block a user