From af1eb58bb87cbb7ce38e01a6fcf96def3222850c Mon Sep 17 00:00:00 2001
From: scorbett123 <50634068+scorbett123@users.noreply.github.com>
Date: Tue, 31 May 2022 14:43:58 +0100
Subject: [PATCH] Implement Leijurv's precomputed data idea
---
src/api/java/baritone/api/Settings.java | 6 +
.../api/event/events/SettingChangedEvent.java | 33 +++
.../listener/AbstractGameEventListener.java | 3 +
.../event/listener/IGameEventListener.java | 7 +
.../java/baritone/api/utils/SettingsUtil.java | 4 +-
.../baritone/behavior/PathingBehavior.java | 17 +-
.../baritone/command/defaults/SetCommand.java | 3 +-
.../java/baritone/event/GameEventHandler.java | 5 +
.../pathing/movement/CalculationContext.java | 8 +-
.../pathing/movement/MovementHelper.java | 3 +
.../movement/movements/MovementAscend.java | 4 +-
.../movement/movements/MovementDescend.java | 12 +-
.../movement/movements/MovementDiagonal.java | 30 +--
.../movement/movements/MovementDownward.java | 2 +-
.../movement/movements/MovementParkour.java | 6 +-
.../movement/movements/MovementPillar.java | 2 +-
.../movement/movements/MovementTraverse.java | 2 +-
.../baritone/pathing/path/PathExecutor.java | 2 +-
.../pathing/precompute/PrecomputedData.java | 237 ++++++++++++++++++
.../PrecomputedDataForBlockState.java | 71 ++++++
.../java/baritone/process/BuilderProcess.java | 3 +-
.../baritone/process/GetToBlockProcess.java | 2 +-
.../java/baritone/process/MineProcess.java | 2 +-
23 files changed, 422 insertions(+), 42 deletions(-)
create mode 100644 src/api/java/baritone/api/event/events/SettingChangedEvent.java
create mode 100644 src/main/java/baritone/pathing/precompute/PrecomputedData.java
create mode 100644 src/main/java/baritone/pathing/precompute/PrecomputedDataForBlockState.java
diff --git a/src/api/java/baritone/api/Settings.java b/src/api/java/baritone/api/Settings.java
index 89718289..1ce87c68 100644
--- a/src/api/java/baritone/api/Settings.java
+++ b/src/api/java/baritone/api/Settings.java
@@ -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;
}
diff --git a/src/api/java/baritone/api/event/events/SettingChangedEvent.java b/src/api/java/baritone/api/event/events/SettingChangedEvent.java
new file mode 100644
index 00000000..d92384e0
--- /dev/null
+++ b/src/api/java/baritone/api/event/events/SettingChangedEvent.java
@@ -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 .
+ */
+
+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;
+ }
+}
diff --git a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
index 9eac8de4..9f1d2418 100644
--- a/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
+++ b/src/api/java/baritone/api/event/listener/AbstractGameEventListener.java
@@ -71,4 +71,7 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override
default void onPathEvent(PathEvent event) {}
+
+ @Override
+ default void onSettingChanged(SettingChangedEvent event) {}
}
diff --git a/src/api/java/baritone/api/event/listener/IGameEventListener.java b/src/api/java/baritone/api/event/listener/IGameEventListener.java
index b074e978..28afdfff 100644
--- a/src/api/java/baritone/api/event/listener/IGameEventListener.java
+++ b/src/api/java/baritone/api/event/listener/IGameEventListener.java
@@ -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);
}
diff --git a/src/api/java/baritone/api/utils/SettingsUtil.java b/src/api/java/baritone/api/utils/SettingsUtil.java
index 0e95965f..b098c1e0 100644
--- a/src/api/java/baritone/api/utils/SettingsUtil.java
+++ b/src/api/java/baritone/api/utils/SettingsUtil.java
@@ -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 {
diff --git a/src/main/java/baritone/behavior/PathingBehavior.java b/src/main/java/baritone/behavior/PathingBehavior.java
index f9c56c5a..50e2a0c2 100644
--- a/src/main/java/baritone/behavior/PathingBehavior.java
+++ b/src/main/java/baritone/behavior/PathingBehavior.java
@@ -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 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
*
diff --git a/src/main/java/baritone/command/defaults/SetCommand.java b/src/main/java/baritone/command/defaults/SetCommand.java
index e9e35d41..1b395f5a 100644
--- a/src/main/java/baritone/command/defaults/SetCommand.java
+++ b/src/main/java/baritone/command/defaults/SetCommand.java
@@ -147,7 +147,8 @@ public class SetCommand extends Command {
throw new CommandInvalidTypeException(args.consumed(), "a toggleable setting", "some other setting");
}
//noinspection unchecked
- ((Settings.Setting) setting).value ^= true;
+ Settings.Setting asBoolSetting = (Settings.Setting) setting;
+ asBoolSetting.set(!asBoolSetting.value);
logDirect(String.format(
"Toggled setting %s to %s",
setting.getName(),
diff --git a/src/main/java/baritone/event/GameEventHandler.java b/src/main/java/baritone/event/GameEventHandler.java
index 8916f7f3..1bdba6b9 100644
--- a/src/main/java/baritone/event/GameEventHandler.java
+++ b/src/main/java/baritone/event/GameEventHandler.java
@@ -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);
diff --git a/src/main/java/baritone/pathing/movement/CalculationContext.java b/src/main/java/baritone/pathing/movement/CalculationContext.java
index d5d6c93c..b4782fb5 100644
--- a/src/main/java/baritone/pathing/movement/CalculationContext.java
+++ b/src/main/java/baritone/pathing/movement/CalculationContext.java
@@ -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();
diff --git a/src/main/java/baritone/pathing/movement/MovementHelper.java b/src/main/java/baritone/pathing/movement/MovementHelper.java
index dd0ddff4..197f1057 100644
--- a/src/main/java/baritone/pathing/movement/MovementHelper.java
+++ b/src/main/java/baritone/pathing/movement/MovementHelper.java
@@ -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
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
index 161ffdac..bbc09f52 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementAscend.java
@@ -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
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
index 128d1bf9..d0f7d9b3 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDescend.java
@@ -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)) {
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
index 933c8609..45d319eb 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDiagonal.java
@@ -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;
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
index da5e3f89..d10a7d26 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementDownward.java
@@ -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);
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java
index e5d17b9a..07140cf1 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementParkour.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementParkour.java
@@ -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;
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
index b9d59933..bcd420ec 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementPillar.java
@@ -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
diff --git a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
index 1ecf0f92..2afce2f4 100644
--- a/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
+++ b/src/main/java/baritone/pathing/movement/movements/MovementTraverse.java
@@ -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())) {
diff --git a/src/main/java/baritone/pathing/path/PathExecutor.java b/src/main/java/baritone/pathing/path/PathExecutor.java
index 7e4f76a3..b28abb61 100644
--- a/src/main/java/baritone/pathing/path/PathExecutor.java
+++ b/src/main/java/baritone/pathing/path/PathExecutor.java
@@ -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);
diff --git a/src/main/java/baritone/pathing/precompute/PrecomputedData.java b/src/main/java/baritone/pathing/precompute/PrecomputedData.java
new file mode 100644
index 00000000..7531c21a
--- /dev/null
+++ b/src/main/java/baritone/pathing/precompute/PrecomputedData.java
@@ -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 .
+ */
+
+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);
+ }
+}
diff --git a/src/main/java/baritone/pathing/precompute/PrecomputedDataForBlockState.java b/src/main/java/baritone/pathing/precompute/PrecomputedDataForBlockState.java
new file mode 100644
index 00000000..c7a2f67d
--- /dev/null
+++ b/src/main/java/baritone/pathing/precompute/PrecomputedDataForBlockState.java
@@ -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 .
+ */
+
+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> precomputer;
+
+ public PrecomputedDataForBlockState(Function> 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 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);
+ }
+}
diff --git a/src/main/java/baritone/process/BuilderProcess.java b/src/main/java/baritone/process/BuilderProcess.java
index 1766af62..39c22248 100644
--- a/src/main/java/baritone/process/BuilderProcess.java
+++ b/src/main/java/baritone/process/BuilderProcess.java
@@ -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();
diff --git a/src/main/java/baritone/process/GetToBlockProcess.java b/src/main/java/baritone/process/GetToBlockProcess.java
index 16fc3dda..2d1e0e98 100644
--- a/src/main/java/baritone/process/GetToBlockProcess.java
+++ b/src/main/java/baritone/process/GetToBlockProcess.java
@@ -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
diff --git a/src/main/java/baritone/process/MineProcess.java b/src/main/java/baritone/process/MineProcess.java
index 1ec47cd9..98808934 100644
--- a/src/main/java/baritone/process/MineProcess.java
+++ b/src/main/java/baritone/process/MineProcess.java
@@ -111,7 +111,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value;
List 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) {