Merge remote-tracking branch 'upstream/master' into pr/frostwalker

This commit is contained in:
ZacSharp 2022-12-30 15:57:17 +01:00
commit b2f66241d5
No known key found for this signature in database
GPG Key ID: 9453647B005083A3
38 changed files with 1288 additions and 105 deletions

View File

@ -209,8 +209,8 @@ public class ProguardTask extends BaritoneGradleTask {
// Setup the template that will be used to derive the API and Standalone configs // Setup the template that will be used to derive the API and Standalone configs
List<String> template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST)); List<String> template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST));
template.add(0, "-injars " + this.artifactPath.toString()); template.add(0, "-injars '" + this.artifactPath.toString() + "'");
template.add(1, "-outjars " + this.getTemporaryFile(PROGUARD_EXPORT_PATH)); template.add(1, "-outjars '" + this.getTemporaryFile(PROGUARD_EXPORT_PATH) + "'");
// Acquire the RT jar using "java -verbose". This doesn't work on Java 9+ // Acquire the RT jar using "java -verbose". This doesn't work on Java 9+
Process p = new ProcessBuilder(this.getJavaBinPathForProguard(), "-verbose").start(); Process p = new ProcessBuilder(this.getJavaBinPathForProguard(), "-verbose").start();
@ -405,9 +405,15 @@ public class ProguardTask extends BaritoneGradleTask {
Files.delete(this.proguardOut); Files.delete(this.proguardOut);
} }
Path proguardJar = getTemporaryFile(PROGUARD_JAR); // Make paths relative to work directory; fixes spaces in path to config, @"" doesn't work
Path workingDirectory = getTemporaryFile("");
Path proguardJar = workingDirectory.relativize(getTemporaryFile(PROGUARD_JAR));
config = workingDirectory.relativize(config);
// Honestly, if you still have spaces in your path at this point, you're SOL.
Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString()) Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString())
.directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder] .directory(workingDirectory.toFile()) // Set the working directory to the temporary folder]
.start(); .start();
// We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this // We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this

View File

@ -42,8 +42,10 @@
#try to keep usage of schematica in separate classes #try to keep usage of schematica in separate classes
-keep class baritone.utils.schematic.schematica.** -keep class baritone.utils.schematic.schematica.**
-keep class baritone.utils.schematic.litematica.**
#proguard doesnt like it when it cant find our fake schematica classes #proguard doesnt like it when it cant find our fake schematica classes
-dontwarn baritone.utils.schematic.schematica.** -dontwarn baritone.utils.schematic.schematica.**
-dontwarn baritone.utils.schematic.litematica.**
# copy all necessary libraries into tempLibraries to build # copy all necessary libraries into tempLibraries to build

View File

@ -34,8 +34,8 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List; import java.util.List;
import java.util.*; import java.util.*;
import java.util.function.Consumer;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.function.Consumer;
/** /**
* Baritone's settings. Settings apply to all Baritone instances. * Baritone's settings. Settings apply to all Baritone instances.
@ -198,7 +198,7 @@ public final class Settings {
* Blocks that Baritone is not allowed to break * Blocks that Baritone is not allowed to break
*/ */
public final Setting<List<Block>> blocksToDisallowBreaking = new Setting<>(new ArrayList<>( public final Setting<List<Block>> blocksToDisallowBreaking = new Setting<>(new ArrayList<>(
// Leave Empty by Default // Leave Empty by Default
)); ));
/** /**
@ -281,6 +281,12 @@ public final class Settings {
*/ */
public final Setting<Boolean> buildIgnoreDirection = new Setting<>(false); public final Setting<Boolean> buildIgnoreDirection = new Setting<>(false);
/**
* A list of names of block properties the builder will ignore.
*/
public final Setting<List<String>> buildIgnoreProperties = new Setting<>(new ArrayList<>(Arrays.asList(
)));
/** /**
* If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block. * If this setting is true, Baritone will never break a block that is adjacent to an unsupported falling block.
* <p> * <p>
@ -914,7 +920,7 @@ public final class Settings {
/** /**
* Only build the selected part of schematics * Only build the selected part of schematics
*/ */
public final Setting<Boolean> buildOnlySelection = new Setting<>(false); public final Setting<Boolean> buildOnlySelection = new Setting<>(false);
/** /**
* How far to move before repeating the build. 0 to disable repeating on a certain axis, 0,0,0 to disable entirely * How far to move before repeating the build. 0 to disable repeating on a certain axis, 0,0,0 to disable entirely

View File

@ -26,7 +26,8 @@ import java.util.stream.Stream;
public enum RelativeCoordinate implements IDatatypePost<Double, Double> { public enum RelativeCoordinate implements IDatatypePost<Double, Double> {
INSTANCE; INSTANCE;
private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)([k-k]?)|)$"); private static String ScalesAliasRegex = "[kKmM]";
private static Pattern PATTERN = Pattern.compile("^(~?)([+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)("+ScalesAliasRegex+"?)|)$");
@Override @Override
public Double apply(IDatatypeContext ctx, Double origin) throws CommandException { public Double apply(IDatatypeContext ctx, Double origin) throws CommandException {
@ -41,11 +42,15 @@ public enum RelativeCoordinate implements IDatatypePost<Double, Double> {
boolean isRelative = !matcher.group(1).isEmpty(); boolean isRelative = !matcher.group(1).isEmpty();
double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll("k", "")); double offset = matcher.group(2).isEmpty() ? 0 : Double.parseDouble(matcher.group(2).replaceAll(ScalesAliasRegex, ""));
if (matcher.group(2).contains("k")) { if (matcher.group(2).toLowerCase().contains("k")) {
offset *= 1000; offset *= 1000;
} }
if (matcher.group(2).toLowerCase().contains("m")) {
offset *= 1000000;
}
if (isRelative) { if (isRelative) {
return origin + offset; return origin + offset;

View File

@ -84,7 +84,7 @@ public class Registry<V> {
* @param entry The entry to unregister. * @param entry The entry to unregister.
*/ */
public void unregister(V entry) { public void unregister(V entry) {
if (registered(entry)) { if (!registered(entry)) {
return; return;
} }
_entries.remove(entry); _entries.remove(entry);

View File

@ -58,6 +58,8 @@ public interface IBuilderProcess extends IBaritoneProcess {
void buildOpenSchematic(); void buildOpenSchematic();
void buildOpenLitematic(int i);
void pause(); void pause();
boolean isPaused(); boolean isPaused();

View File

@ -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 * 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 * @return true if the setting can not be set or read by the user
*/ */
public static boolean javaOnlySetting(Settings.Setting setting) { public static boolean javaOnlySetting(Settings.Setting setting) {

View File

@ -0,0 +1,35 @@
/*
* 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.launch.mixins;
import baritone.utils.accessor.INBTTagLongArray;
import net.minecraft.nbt.NBTTagLongArray;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
/**
* @author rycbar
* @since 26.09.2022
*/
@Mixin(NBTTagLongArray.class)
public abstract class MixinNBTTagLongArray implements INBTTagLongArray {
@Accessor("data")
@Override
public abstract long[] getLongArray();
}

View File

@ -23,6 +23,7 @@
"MixinItemStack", "MixinItemStack",
"MixinItemTool", "MixinItemTool",
"MixinMinecraft", "MixinMinecraft",
"MixinNBTTagLongArray",
"MixinNetHandlerPlayClient", "MixinNetHandlerPlayClient",
"MixinNetworkManager", "MixinNetworkManager",
"MixinPlayerControllerMP", "MixinPlayerControllerMP",

View File

@ -99,6 +99,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
baritone.getPathingControlManager().cancelEverything(); baritone.getPathingControlManager().cancelEverything();
return; return;
} }
expectedSegmentStart = pathStart(); expectedSegmentStart = pathStart();
baritone.getPathingControlManager().preTick(); baritone.getPathingControlManager().preTick();
tickPath(); tickPath();

View File

@ -43,6 +43,7 @@ public final class DefaultCommands {
new RepackCommand(baritone), new RepackCommand(baritone),
new BuildCommand(baritone), new BuildCommand(baritone),
new SchematicaCommand(baritone), new SchematicaCommand(baritone),
new LitematicaCommand(baritone),
new ComeCommand(baritone), new ComeCommand(baritone),
new AxisCommand(baritone), new AxisCommand(baritone),
new ForceCancelCommand(baritone), new ForceCancelCommand(baritone),

View File

@ -56,6 +56,7 @@ public class ExecutionControlCommands {
@Override @Override
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) { public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
baritone.getInputOverrideHandler().clearAllKeys();
return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE); return new PathingCommand(null, PathingCommandType.REQUEST_PAUSE);
} }

View File

@ -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.command.defaults;
import baritone.api.IBaritone;
import baritone.api.command.Command;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
public class LitematicaCommand extends Command {
public LitematicaCommand(IBaritone baritone) {
super(baritone, "litematica");
}
@Override
public void execute(String label, IArgConsumer args) throws CommandException {
int schematic = 0;
if (args.hasAny()) {
args.requireMax(1);
if (args.is(Integer.class)) {
schematic = args.getAs(Integer.class) - 1;
}
}
try {
baritone.getBuilderProcess().buildOpenLitematic(schematic);
} catch (IndexOutOfBoundsException e) {
logDirect("Pleas provide a valid index.");
}
}
@Override
public Stream<String> tabComplete(String label, IArgConsumer args) {
return Stream.empty();
}
@Override
public String getShortDesc() {
return "Builds the loaded schematic";
}
@Override
public List<String> getLongDesc() {
return Arrays.asList(
"Build a schematic currently open in Litematica.",
"",
"Usage:",
"> litematica",
"> litematica <#>"
);
}
}

View File

@ -147,7 +147,8 @@ public class SetCommand extends Command {
throw new CommandInvalidTypeException(args.consumed(), "a toggleable setting", "some other setting"); throw new CommandInvalidTypeException(args.consumed(), "a toggleable setting", "some other setting");
} }
//noinspection unchecked //noinspection unchecked
((Settings.Setting<Boolean>) setting).value ^= true; Settings.Setting<Boolean> asBoolSetting = (Settings.Setting<Boolean>) setting;
asBoolSetting.value ^= true;
logDirect(String.format( logDirect(String.format(
"Toggled setting %s to %s", "Toggled setting %s to %s",
setting.getName(), setting.getName(),

View File

@ -21,6 +21,7 @@ import baritone.Baritone;
import baritone.api.IBaritone; import baritone.api.IBaritone;
import baritone.api.pathing.movement.ActionCosts; import baritone.api.pathing.movement.ActionCosts;
import baritone.cache.WorldData; import baritone.cache.WorldData;
import baritone.pathing.precompute.PrecomputedData;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.ToolSet; import baritone.utils.ToolSet;
import baritone.utils.pathing.BetterWorldBorder; import baritone.utils.pathing.BetterWorldBorder;
@ -78,11 +79,14 @@ public class CalculationContext {
public final double walkOnWaterOnePenalty; public final double walkOnWaterOnePenalty;
public final BetterWorldBorder worldBorder; public final BetterWorldBorder worldBorder;
public final PrecomputedData precomputedData;
public CalculationContext(IBaritone baritone) { public CalculationContext(IBaritone baritone) {
this(baritone, false); this(baritone, false);
} }
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) { public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
this.precomputedData = new PrecomputedData();
this.safeForThreadedUse = forUseOnAnotherThread; this.safeForThreadedUse = forUseOnAnotherThread;
this.baritone = baritone; this.baritone = baritone;
EntityPlayerSP player = baritone.getPlayerContext().player(); EntityPlayerSP player = baritone.getPlayerContext().player();

View File

@ -25,6 +25,7 @@ import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*; import baritone.api.utils.*;
import baritone.api.utils.input.Input; import baritone.api.utils.input.Input;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.pathing.precompute.Ternary;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.ToolSet; import baritone.utils.ToolSet;
import net.minecraft.block.*; import net.minecraft.block.*;
@ -41,6 +42,7 @@ import net.minecraft.world.IBlockAccess;
import java.util.Optional; import java.util.Optional;
import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP; import static baritone.pathing.movement.Movement.HORIZONTALS_BUT_ALSO_DOWN_____SO_EVERY_DIRECTION_EXCEPT_UP;
import static baritone.pathing.precompute.Ternary.*;
/** /**
* Static helpers for cost calculation * Static helpers for cost calculation
@ -89,29 +91,81 @@ public interface MovementHelper extends ActionCosts, Helper {
return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z)); return canWalkThrough(bsi, x, y, z, bsi.get0(x, y, z));
} }
static boolean canWalkThrough(CalculationContext context, int x, int y, int z, IBlockState state) {
return context.precomputedData.canWalkThrough(context.bsi, x, y, z, state);
}
static boolean canWalkThrough(CalculationContext context, int x, int y, int z) {
return context.precomputedData.canWalkThrough(context.bsi, x, y, z, context.get(x, y, z));
}
static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) { static boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock(); Ternary canWalkThrough = canWalkThroughBlockState(state);
if (block == Blocks.AIR) { // early return for most common case if (canWalkThrough == YES) {
return true; return 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) { if (canWalkThrough == NO) {
return false; return false;
} }
return canWalkThroughPosition(bsi, x, y, z, state);
}
static Ternary canWalkThroughBlockState(IBlockState state) {
Block block = state.getBlock();
if (block == Blocks.AIR) {
return YES;
}
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 NO;
}
if (Baritone.settings().blocksToAvoid.value.contains(block)) { if (Baritone.settings().blocksToAvoid.value.contains(block)) {
return false; return NO;
} }
if (block instanceof BlockDoor || block instanceof BlockFenceGate) { 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 // TODO this assumes that all doors in all mods are openable
// that anything that isn't an iron door isn't openable, ignoring that some doors introduced in mods can't if (block == Blocks.IRON_DOOR) {
// be opened by just interacting. return NO;
return block != Blocks.IRON_DOOR; }
return YES;
} }
if (block == Blocks.CARPET) {
return MAYBE;
}
if (block instanceof BlockSnow) {
// snow layers cached as the top layer of a packed chunk have no metadata, we can't make a decision based on their depth here
// it would otherwise make long distance pathing through snowy biomes impossible
return MAYBE;
}
if (block instanceof BlockLiquid) {
if (state.getValue(BlockLiquid.LEVEL) != 0) {
return NO;
} else {
return MAYBE;
}
}
if (block instanceof BlockCauldron) {
return NO;
}
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
if (block.isPassable(null, null)) {
return YES;
} else {
return NO;
}
} catch (Throwable exception) {
System.out.println("The block " + state.getBlock().getLocalizedName() + " requires a special case due to the exception " + exception.getMessage());
return MAYBE;
}
}
static boolean canWalkThroughPosition(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock();
if (block == Blocks.CARPET) { if (block == Blocks.CARPET) {
return canWalkOn(bsi, x, y - 1, z); return canWalkOn(bsi, x, y - 1, z);
} }
if (block instanceof BlockSnow) { if (block instanceof BlockSnow) {
// we've already checked doors and fence gates
// so the only remaining dynamic isPassables are snow and trapdoor
// if they're cached as a top block, we don't know their metadata // if they're cached as a top block, we don't know their metadata
// default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible) // default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
if (!bsi.worldContainsLoadedChunk(x, z)) { if (!bsi.worldContainsLoadedChunk(x, z)) {
@ -125,25 +179,27 @@ public interface MovementHelper extends ActionCosts, Helper {
// ok, it's low enough we could walk through it, but is it supported? // ok, it's low enough we could walk through it, but is it supported?
return canWalkOn(bsi, x, y - 1, z); return canWalkOn(bsi, x, y - 1, z);
} }
if (isFlowing(x, y, z, state, bsi)) {
return false; // Don't walk through flowing liquids
}
if (block instanceof BlockLiquid) { if (block instanceof BlockLiquid) {
if (isFlowing(x, y, z, state, 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) { if (Baritone.settings().assumeWalkOnWater.value) {
return false; return false;
} }
IBlockState up = bsi.get0(x, y + 1, z); IBlockState up = bsi.get0(x, y + 1, z);
if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) { if (up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
return false; return false;
} }
return block == Blocks.WATER || block == Blocks.FLOWING_WATER; return block == Blocks.WATER || block == Blocks.FLOWING_WATER;
} }
if (block instanceof BlockCauldron) {
return false;
}
return block.isPassable(bsi.access, bsi.isPassableBlockPos.setPos(x, y, z)); return block.isPassable(bsi.access, bsi.isPassableBlockPos.setPos(x, y, z));
} }
/** /**
* canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click), * canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click),
* not including water, and not including ladders or vines or cobwebs (they slow us down) * not including water, and not including ladders or vines or cobwebs (they slow us down)
@ -285,6 +341,8 @@ public interface MovementHelper extends ActionCosts, Helper {
* Can I walk on this block without anything weird happening like me falling * Can I walk on this block without anything weird happening like me falling
* through? Includes water because we know that we automatically jump on * through? Includes water because we know that we automatically jump on
* water * water
* <p>
* If changing something in this function remember to also change it in precomputed data
* *
* @param bsi Block state provider * @param bsi Block state provider
* @param x The block's x position * @param x The block's x position
@ -294,32 +352,67 @@ public interface MovementHelper extends ActionCosts, Helper {
* @return Whether or not the specified block can be walked on * @return Whether or not the specified block can be walked on
*/ */
static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) { static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock(); Ternary canWalkOn = canWalkOnBlockState(state);
if (block == Blocks.AIR || block == Blocks.MAGMA) { if (canWalkOn == YES) {
// early return for most common case (air) return true;
// plus magma, which is a normal cube but it hurts you }
if (canWalkOn == NO) {
return false; return false;
} }
if (state.isBlockNormalCube()) { return canWalkOnPosition(bsi, x, y, z, state);
return true; }
static Ternary canWalkOnBlockState(IBlockState state) {
Block block = state.getBlock();
if (state.isBlockNormalCube() && block != Blocks.MAGMA) {
return YES;
} }
if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this if (block == Blocks.LADDER || (block == Blocks.VINE && Baritone.settings().allowVines.value)) { // TODO reconsider this
return true; return YES;
} }
if (block == Blocks.FARMLAND || block == Blocks.GRASS_PATH) { if (block == Blocks.FARMLAND || block == Blocks.GRASS_PATH) {
return true; return YES;
} }
if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) { if (block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST) {
return true; return YES;
}
if (block == Blocks.GLASS || block == Blocks.STAINED_GLASS) {
return YES;
}
if (block instanceof BlockStairs) {
return YES;
} }
if (isWater(block)) {
return MAYBE;
}
if (MovementHelper.isLava(block) && Baritone.settings().assumeWalkOnLava.value) {
return MAYBE;
}
if (block instanceof BlockSlab) {
if (!Baritone.settings().allowWalkOnBottomSlab.value) {
if (((BlockSlab) block).isDouble()) {
return YES;
}
if (state.getValue(BlockSlab.HALF) != BlockSlab.EnumBlockHalf.BOTTOM) {
return YES;
}
return NO;
}
return YES;
}
return NO;
}
static boolean canWalkOnPosition(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
Block block = state.getBlock();
if (isWater(block)) { if (isWater(block)) {
// since this is called literally millions of times per second, the benefit of not allocating millions of useless "pos.up()" // 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 its a decrease in readability // 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(); Block up = bsi.get0(x, y + 1, z).getBlock();
if (up == Blocks.WATERLILY || up == Blocks.CARPET) { if (up == Blocks.WATERLILY || up == Blocks.CARPET) {
return true; return true;
} }
if (isFlowing(x, y, z, state, bsi) || block == Blocks.FLOWING_WATER) { if (MovementHelper.isFlowing(x, y, z, state, 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 // 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; return isWater(up) && !Baritone.settings().assumeWalkOnWater.value;
} }
@ -327,22 +420,20 @@ public interface MovementHelper extends ActionCosts, Helper {
// if assumeWalkOnWater is off, we can only walk on water if there is 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; return isWater(up) ^ Baritone.settings().assumeWalkOnWater.value;
} }
if (Baritone.settings().assumeWalkOnLava.value && isLava(block) && !isFlowing(x, y, z, state, bsi)) {
if (MovementHelper.isLava(block) && !MovementHelper.isFlowing(x, y, z, state, bsi) && Baritone.settings().assumeWalkOnLava.value) { // if we get here it means that assumeWalkOnLava must be true, so put it last
return true; return true;
} }
if (block == Blocks.GLASS || block == Blocks.STAINED_GLASS) {
return true; return false; // If we don't recognise it then we want to just return false to be safe.
} }
if (block instanceof BlockSlab) {
if (!Baritone.settings().allowWalkOnBottomSlab.value) { static boolean canWalkOn(CalculationContext context, int x, int y, int z, IBlockState state) {
if (((BlockSlab) block).isDouble()) { return context.precomputedData.canWalkOn(context.bsi, x, y, z, state);
return true; }
}
return state.getValue(BlockSlab.HALF) != BlockSlab.EnumBlockHalf.BOTTOM; static boolean canWalkOn(CalculationContext context, int x, int y, int z) {
} return canWalkOn(context, x, y, z, context.get(x, y, z));
return true;
}
return block instanceof BlockStairs;
} }
static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos, IBlockState state) { static boolean canWalkOn(IPlayerContext ctx, BetterBlockPos pos, IBlockState state) {
@ -422,7 +513,7 @@ public interface MovementHelper extends ActionCosts, Helper {
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) { static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
Block block = state.getBlock(); Block block = state.getBlock();
if (!canWalkThrough(context.bsi, x, y, z, state)) { if (!canWalkThrough(context, x, y, z, state)) {
if (block instanceof BlockLiquid) { if (block instanceof BlockLiquid) {
return COST_INF; return COST_INF;
} }

View File

@ -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) { public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
IBlockState toPlace = context.get(destX, y, destZ); IBlockState toPlace = context.get(destX, y, destZ);
double additionalPlacementCost = 0; double additionalPlacementCost = 0;
if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) { if (!MovementHelper.canWalkOn(context, destX, y, destZ, toPlace)) {
additionalPlacementCost = context.costOfPlacingAt(destX, y, destZ, toPlace); additionalPlacementCost = context.costOfPlacingAt(destX, y, destZ, toPlace);
if (additionalPlacementCost >= COST_INF) { if (additionalPlacementCost >= COST_INF) {
return 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 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 && (MovementHelper.canWalkThrough(context, 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 // HOWEVER, we assume that we're standing in the start position
// that means that src and src.up(1) are both air // 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 // maybe they aren't now, but they will be by the time this starts

View File

@ -111,7 +111,7 @@ public class MovementDescend extends Movement {
//C, D, etc determine the length of the fall //C, D, etc determine the length of the fall
IBlockState below = context.get(destX, y - 2, destZ); IBlockState below = context.get(destX, y - 2, destZ);
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ, below)) { if (!MovementHelper.canWalkOn(context, destX, y - 2, destZ, below)) {
dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res); dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res);
return; return;
} }
@ -143,7 +143,7 @@ public class MovementDescend extends Movement {
// and potentially replace the water we're going to fall into // and potentially replace the water we're going to fall into
return false; return false;
} }
if (!MovementHelper.canWalkThrough(context.bsi, destX, y - 2, destZ, below)) { if (!MovementHelper.canWalkThrough(context, destX, y - 2, destZ, below)) {
return false; return false;
} }
double costSoFar = 0; double costSoFar = 0;
@ -159,7 +159,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 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; double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar;
if (MovementHelper.isWater(ontoBlock.getBlock())) { if (MovementHelper.isWater(ontoBlock.getBlock())) {
if (!MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) { if (!MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) {
return false; return false;
} }
if (context.assumeWalkOnWater) { if (context.assumeWalkOnWater) {
@ -168,7 +168,7 @@ public class MovementDescend extends Movement {
if (MovementHelper.isFlowing(destX, newY, destZ, ontoBlock, context.bsi)) { if (MovementHelper.isFlowing(destX, newY, destZ, ontoBlock, context.bsi)) {
return false; // TODO flowing check required here? return false; // TODO flowing check required here?
} }
if (!MovementHelper.canWalkOn(context.bsi, destX, newY - 1, destZ)) { if (!MovementHelper.canWalkOn(context, destX, newY - 1, destZ)) {
// we could punch right through the water into something else // we could punch right through the water into something else
return false; return false;
} }
@ -187,10 +187,10 @@ public class MovementDescend extends Movement {
effectiveStartHeight = newY; effectiveStartHeight = newY;
continue; continue;
} }
if (MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) { if (MovementHelper.canWalkThrough(context, destX, newY, destZ, ontoBlock)) {
continue; continue;
} }
if (!MovementHelper.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) { if (!MovementHelper.canWalkOn(context, destX, newY, destZ, ontoBlock)) {
return false; return false;
} }
if (MovementHelper.isBottomSlab(ontoBlock)) { if (MovementHelper.isBottomSlab(ontoBlock)) {

View File

@ -61,7 +61,7 @@ public class MovementDiagonal extends Movement {
@Override @Override
protected boolean safeToCancel(MovementState state) { protected boolean safeToCancel(MovementState state) {
//too simple. backfill does not work after cornering with this //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(); EntityPlayerSP player = ctx.player();
double offset = 0.25; double offset = 0.25;
double x = player.posX; double x = player.posX;
@ -111,7 +111,7 @@ public class MovementDiagonal extends Movement {
} }
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) { 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 (!MovementHelper.canWalkThrough(context, destX, y + 1, destZ)) {
return; return;
} }
IBlockState destInto = context.get(destX, y, destZ); IBlockState destInto = context.get(destX, y, destZ);
@ -119,9 +119,9 @@ public class MovementDiagonal extends Movement {
IBlockState destWalkOn; IBlockState destWalkOn;
boolean descend = false; boolean descend = false;
boolean frostWalker = false; boolean frostWalker = false;
if (!MovementHelper.canWalkThrough(context.bsi, destX, y, destZ, destInto)) { if (!MovementHelper.canWalkThrough(context, destX, y, destZ, destInto)) {
ascend = true; 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 || !MovementHelper.canWalkThrough(context, x, y + 2, z) || !MovementHelper.canWalkOn(context, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context, destX, y + 2, destZ)) {
return; return;
} }
destWalkOn = destInto; destWalkOn = destInto;
@ -129,9 +129,9 @@ public class MovementDiagonal extends Movement {
destWalkOn = context.get(destX, y - 1, destZ); destWalkOn = context.get(destX, y - 1, destZ);
boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y-1, z, context.get(x, y-1, z)); boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y-1, z, context.get(x, y-1, z));
frostWalker = standingOnABlock && MovementHelper.canUseFrostWalker(context, destWalkOn); frostWalker = standingOnABlock && MovementHelper.canUseFrostWalker(context, destWalkOn);
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn) && !frostWalker) { if (!MovementHelper.canWalkOn(context, destX, y - 1, destZ, destWalkOn) && !frostWalker) {
descend = true; 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 || !MovementHelper.canWalkOn(context, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context, destX, y - 1, destZ, destWalkOn)) {
return; return;
} }
} }
@ -176,17 +176,17 @@ public class MovementDiagonal extends Movement {
IBlockState pb0 = context.get(x, y, destZ); IBlockState pb0 = context.get(x, y, destZ);
IBlockState pb2 = context.get(destX, y, z); IBlockState pb2 = context.get(destX, y, z);
if (ascend) { if (ascend) {
boolean ATop = MovementHelper.canWalkThrough(context.bsi, x, y + 2, destZ); boolean ATop = MovementHelper.canWalkThrough(context, x, y + 2, destZ);
boolean AMid = MovementHelper.canWalkThrough(context.bsi, x, y + 1, destZ); boolean AMid = MovementHelper.canWalkThrough(context, x, y + 1, destZ);
boolean ALow = MovementHelper.canWalkThrough(context.bsi, x, y, destZ, pb0); boolean ALow = MovementHelper.canWalkThrough(context, x, y, destZ, pb0);
boolean BTop = MovementHelper.canWalkThrough(context.bsi, destX, y + 2, z); boolean BTop = MovementHelper.canWalkThrough(context, destX, y + 2, z);
boolean BMid = MovementHelper.canWalkThrough(context.bsi, destX, y + 1, z); boolean BMid = MovementHelper.canWalkThrough(context, destX, y + 1, z);
boolean BLow = MovementHelper.canWalkThrough(context.bsi, destX, y, z, pb2); boolean BLow = MovementHelper.canWalkThrough(context, destX, y, z, pb2);
if ((!(ATop && AMid && ALow) && !(BTop && BMid && BLow)) // no option if ((!(ATop && AMid && ALow) && !(BTop && BMid && BLow)) // no option
|| MovementHelper.avoidWalkingInto(pb0.getBlock()) // bad || MovementHelper.avoidWalkingInto(pb0.getBlock()) // bad
|| MovementHelper.avoidWalkingInto(pb2.getBlock()) // bad || MovementHelper.avoidWalkingInto(pb2.getBlock()) // bad
|| (ATop && AMid && MovementHelper.canWalkOn(context.bsi, x, y, destZ, pb0)) // we could just ascend || (ATop && AMid && MovementHelper.canWalkOn(context, x, y, destZ, pb0)) // we could just ascend
|| (BTop && BMid && MovementHelper.canWalkOn(context.bsi, destX, y, z, pb2)) // we could just ascend || (BTop && BMid && MovementHelper.canWalkOn(context, destX, y, z, pb2)) // we could just ascend
|| (!ATop && AMid && ALow) // head bonk A || (!ATop && AMid && ALow) // head bonk A
|| (!BTop && BMid && BLow)) { // head bonk B || (!BTop && BMid && BLow)) { // head bonk B
return; return;

View File

@ -59,7 +59,7 @@ public class MovementDownward extends Movement {
if (!context.allowDownward) { if (!context.allowDownward) {
return COST_INF; return COST_INF;
} }
if (!MovementHelper.canWalkOn(context.bsi, x, y - 2, z)) { if (!MovementHelper.canWalkOn(context, x, y - 2, z)) {
return COST_INF; return COST_INF;
} }
IBlockState down = context.get(x, y - 1, z); IBlockState down = context.get(x, y - 1, z);

View File

@ -75,7 +75,7 @@ public class MovementParkour extends Movement {
return; return;
} }
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff); 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 (MovementHelper.canWalkOn(context, 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 // second most common case -- we could just traverse not parkour
return; return;
} }
@ -130,7 +130,7 @@ public class MovementParkour extends Movement {
// check for ascend landing position // check for ascend landing position
IBlockState destInto = context.bsi.get0(destX, y, destZ); IBlockState destInto = context.bsi.get0(destX, y, destZ);
if (!MovementHelper.fullyPassable(context.bsi.access, context.bsi.isPassableBlockPos.setPos(destX, y, destZ), destInto)) { 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 && MovementHelper.canWalkOn(context, destX, y, destZ, destInto) && checkOvershootSafety(context.bsi, destX + xDiff, y + 1, destZ + zDiff)) {
res.x = destX; res.x = destX;
res.y = y + 1; res.y = y + 1;
res.z = destZ; res.z = destZ;
@ -144,7 +144,7 @@ public class MovementParkour extends Movement {
IBlockState landingOn = context.bsi.get0(destX, y - 1, destZ); 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 // farmland needs to be canWalkOn otherwise farm can never work at all, but we want to specifically disallow ending a jump on farmland haha
// frostwalker works here because we can't jump from possibly unfrozen water // frostwalker works here because we can't jump from possibly unfrozen water
if ((landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, landingOn)) if ((landingOn.getBlock() != Blocks.FARMLAND && MovementHelper.canWalkOn(context, destX, y - 1, destZ, landingOn))
|| (Math.min(16, context.frostWalker + 2) >= i && MovementHelper.canUseFrostWalker(context, landingOn)) || (Math.min(16, context.frostWalker + 2) >= i && MovementHelper.canUseFrostWalker(context, landingOn))
) { ) {
if (checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) { if (checkOvershootSafety(context.bsi, destX + xDiff, y, destZ + zDiff)) {

View File

@ -124,7 +124,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. // 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 (!MovementHelper.canWalkOn(context, chkPos, check) || MovementHelper.canWalkThrough(context, 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? // TODO why does canWalkThrough mean this action is COST_INF?
// BlockFalling makes sense, and !canWalkOn deals with weird cases like if it were lava // BlockFalling makes sense, and !canWalkOn deals with weird cases like if it were lava
// but I don't understand why canWalkThrough makes it impossible // but I don't understand why canWalkThrough makes it impossible

View File

@ -75,7 +75,7 @@ public class MovementTraverse extends Movement {
Block srcDown = context.getBlock(x, y - 1, z); Block srcDown = context.getBlock(x, y - 1, z);
boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y-1, z, context.get(x, y-1, z)); boolean standingOnABlock = MovementHelper.mustBeSolidToWalkOn(context, x, y-1, z, context.get(x, y-1, z));
boolean frostWalker = standingOnABlock && !context.assumeWalkOnWater && MovementHelper.canUseFrostWalker(context, destOn); boolean frostWalker = standingOnABlock && !context.assumeWalkOnWater && MovementHelper.canUseFrostWalker(context, destOn);
if (MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destOn) || frostWalker) { //this is a walk, not a bridge if (MovementHelper.canWalkOn(context, destX, y - 1, destZ, destOn) || frostWalker) { //this is a walk, not a bridge
double WC = WALK_ONE_BLOCK_COST; double WC = WALK_ONE_BLOCK_COST;
boolean water = false; boolean water = false;
if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) { if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) {

View File

@ -350,7 +350,7 @@ public class PathExecutor implements IPathExecutor, Helper {
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false); 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 // 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).canSprint) {
return false; return false;
} }
IMovement current = path.movements().get(pathPosition); IMovement current = path.movements().get(pathPosition);

View File

@ -0,0 +1,92 @@
/*
* 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.pathing.movement.MovementHelper;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import static baritone.pathing.precompute.Ternary.MAYBE;
import static baritone.pathing.precompute.Ternary.YES;
public class PrecomputedData { // TODO add isFullyPassable
private final int[] data = new int[Block.BLOCK_STATE_IDS.size()];
private static final int COMPLETED_MASK = 1 << 0;
private static final int CAN_WALK_ON_MASK = 1 << 1;
private static final int CAN_WALK_ON_SPECIAL_MASK = 1 << 2;
private static final int CAN_WALK_THROUGH_MASK = 1 << 3;
private static final int CAN_WALK_THROUGH_SPECIAL_MASK = 1 << 4;
private int fillData(int id, IBlockState state) {
int blockData = 0;
Ternary canWalkOnState = MovementHelper.canWalkOnBlockState(state);
if (canWalkOnState == YES) {
blockData |= CAN_WALK_ON_MASK;
}
if (canWalkOnState == MAYBE) {
blockData |= CAN_WALK_ON_SPECIAL_MASK;
}
Ternary canWalkThroughState = MovementHelper.canWalkThroughBlockState(state);
if (canWalkThroughState == YES) {
blockData |= CAN_WALK_THROUGH_MASK;
}
if (canWalkOnState == MAYBE) {
blockData |= CAN_WALK_THROUGH_SPECIAL_MASK;
}
blockData |= COMPLETED_MASK;
data[id] = blockData; // in theory, this is thread "safe" because every thread should compute the exact same int to write?
return blockData;
}
public boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
int id = Block.BLOCK_STATE_IDS.get(state);
int blockData = data[id];
if ((blockData & COMPLETED_MASK) == 0) { // we need to fill in the data
blockData = fillData(id, state);
}
if ((blockData & CAN_WALK_ON_SPECIAL_MASK) != 0) {
return MovementHelper.canWalkOnPosition(bsi, x, y, z, state);
} else {
return (blockData & CAN_WALK_ON_MASK) != 0;
}
}
public boolean canWalkThrough(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
int id = Block.BLOCK_STATE_IDS.get(state);
int blockData = data[id];
if ((blockData & COMPLETED_MASK) == 0) { // we need to fill in the data
blockData = fillData(id, state);
}
if ((blockData & CAN_WALK_THROUGH_SPECIAL_MASK) != 0) {
return MovementHelper.canWalkThroughPosition(bsi, x, y, z, state);
} else {
return (blockData & CAN_WALK_THROUGH_MASK) != 0;
}
}
}

View File

@ -0,0 +1,22 @@
/*
* 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;
public enum Ternary {
YES, MAYBE, NO
}

View File

@ -56,12 +56,12 @@ public final class BackfillProcess extends BaritoneProcessHelper {
Baritone.settings().backfill.value = false; Baritone.settings().backfill.value = false;
return false; return false;
} }
amIBreakingABlockHMMMMMMM();
for (BlockPos pos : new ArrayList<>(blocksToReplace.keySet())) { for (BlockPos pos : new ArrayList<>(blocksToReplace.keySet())) {
if (ctx.world().getChunk(pos) instanceof EmptyChunk) { if (ctx.world().getChunk(pos) instanceof EmptyChunk || ctx.world().getBlockState(pos).getBlock() != Blocks.AIR) {
blocksToReplace.remove(pos); blocksToReplace.remove(pos);
} }
} }
amIBreakingABlockHMMMMMMM();
baritone.getInputOverrideHandler().clearAllKeys(); baritone.getInputOverrideHandler().clearAllKeys();
return !toFillIn().isEmpty(); return !toFillIn().isEmpty();
@ -93,7 +93,7 @@ public final class BackfillProcess extends BaritoneProcessHelper {
} }
private void amIBreakingABlockHMMMMMMM() { private void amIBreakingABlockHMMMMMMM() {
if (!ctx.getSelectedBlock().isPresent()) { if (!ctx.getSelectedBlock().isPresent() || !baritone.getPathingBehavior().isPathing()) {
return; return;
} }
blocksToReplace.put(ctx.getSelectedBlock().get(), ctx.world().getBlockState(ctx.getSelectedBlock().get())); blocksToReplace.put(ctx.getSelectedBlock().get(), ctx.world().getBlockState(ctx.getSelectedBlock().get()));

View File

@ -26,9 +26,9 @@ import baritone.api.process.IBuilderProcess;
import baritone.api.process.PathingCommand; import baritone.api.process.PathingCommand;
import baritone.api.process.PathingCommandType; import baritone.api.process.PathingCommandType;
import baritone.api.schematic.FillSchematic; import baritone.api.schematic.FillSchematic;
import baritone.api.schematic.SubstituteSchematic;
import baritone.api.schematic.ISchematic; import baritone.api.schematic.ISchematic;
import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.SubstituteSchematic;
import baritone.api.schematic.format.ISchematicFormat; import baritone.api.schematic.format.ISchematicFormat;
import baritone.api.utils.BetterBlockPos; import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RayTraceUtils; import baritone.api.utils.RayTraceUtils;
@ -42,8 +42,10 @@ import baritone.utils.BaritoneProcessHelper;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.PathingCommandContext; import baritone.utils.PathingCommandContext;
import baritone.utils.schematic.MapArtSchematic; import baritone.utils.schematic.MapArtSchematic;
import baritone.utils.schematic.SelectionSchematic;
import baritone.utils.schematic.SchematicSystem; import baritone.utils.schematic.SchematicSystem;
import baritone.utils.schematic.SelectionSchematic;
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import baritone.utils.schematic.litematica.LitematicaHelper;
import baritone.utils.schematic.schematica.SchematicaHelper; import baritone.utils.schematic.schematica.SchematicaHelper;
import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSet;
@ -54,12 +56,15 @@ import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.item.ItemBlock; import net.minecraft.item.ItemBlock;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompressedStreamTools;
import net.minecraft.util.EnumFacing; import net.minecraft.util.EnumFacing;
import net.minecraft.util.Tuple; import net.minecraft.util.Tuple;
import net.minecraft.util.math.*; import net.minecraft.util.math.*;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -176,6 +181,33 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
} }
} }
/**
* Builds the with index 'i' given schematic placement.
*
* @param i index reference to the schematic placement list.
*/
@Override
public void buildOpenLitematic(int i) {
if (LitematicaHelper.isLitematicaPresent()) {
//if java.lang.NoSuchMethodError is thrown see comment in SchematicPlacementManager
if (LitematicaHelper.hasLoadedSchematic()) {
String name = LitematicaHelper.getName(i);
try {
LitematicaSchematic schematic1 = new LitematicaSchematic(CompressedStreamTools.readCompressed(Files.newInputStream(LitematicaHelper.getSchematicFile(i).toPath())), false);
Vec3i correctedOrigin = LitematicaHelper.getCorrectedOrigin(schematic1, i);
LitematicaSchematic schematic2 = LitematicaHelper.blackMagicFuckery(schematic1, i);
build(name, schematic2, correctedOrigin);
} catch (IOException e) {
logDirect("Schematic File could not be loaded.");
}
} else {
logDirect("No schematic currently loaded");
}
} else {
logDirect("Litematica is not present");
}
}
public void clearArea(BlockPos corner1, BlockPos corner2) { public void clearArea(BlockPos corner1, BlockPos corner2) {
BlockPos origin = new BlockPos(Math.min(corner1.getX(), corner2.getX()), Math.min(corner1.getY(), corner2.getY()), Math.min(corner1.getZ(), corner2.getZ())); BlockPos origin = new BlockPos(Math.min(corner1.getX(), corner2.getX()), Math.min(corner1.getY(), corner2.getY()), Math.min(corner1.getZ(), corner2.getZ()));
int widthX = Math.abs(corner1.getX() - corner2.getX()) + 1; int widthX = Math.abs(corner1.getX() - corner2.getX()) + 1;
@ -606,7 +638,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
} }
// this is not in render distance // this is not in render distance
if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ)) if (!observedCompleted.contains(BetterBlockPos.longHash(blockX, blockY, blockZ))
&& !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) { && !Baritone.settings().buildSkipBlocks.value.contains(schematic.desiredState(x, y, z, current, this.approxPlaceable).getBlock())) {
// and we've never seen this position be correct // and we've never seen this position be correct
// therefore mark as incorrect // therefore mark as incorrect
incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ)); incorrectPositions.add(new BetterBlockPos(blockX, blockY, blockZ));
@ -842,14 +874,21 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
BlockTrapDoor.OPEN, BlockTrapDoor.HALF BlockTrapDoor.OPEN, BlockTrapDoor.HALF
); );
private boolean sameWithoutOrientation(IBlockState first, IBlockState second) { private boolean sameBlockstate(IBlockState first, IBlockState second) {
if (first.getBlock() != second.getBlock()) { if (first.getBlock() != second.getBlock()) {
return false; return false;
} }
boolean ignoreDirection = Baritone.settings().buildIgnoreDirection.value;
List<String> ignoredProps = Baritone.settings().buildIgnoreProperties.value;
if (!ignoreDirection && ignoredProps.isEmpty()) {
return first.equals(second); // early return if no properties are being ignored
}
ImmutableMap<IProperty<?>, Comparable<?>> map1 = first.getProperties(); ImmutableMap<IProperty<?>, Comparable<?>> map1 = first.getProperties();
ImmutableMap<IProperty<?>, Comparable<?>> map2 = second.getProperties(); ImmutableMap<IProperty<?>, Comparable<?>> map2 = second.getProperties();
for (IProperty<?> prop : map1.keySet()) { for (IProperty<?> prop : map1.keySet()) {
if (map1.get(prop) != map2.get(prop) && !orientationProps.contains(prop)) { if (map1.get(prop) != map2.get(prop)
&& !(ignoreDirection && orientationProps.contains(prop))
&& !ignoredProps.contains(prop.getName())) {
return false; return false;
} }
} }
@ -881,7 +920,7 @@ public final class BuilderProcess extends BaritoneProcessHelper implements IBuil
if (current.equals(desired)) { if (current.equals(desired)) {
return true; return true;
} }
return Baritone.settings().buildIgnoreDirection.value && sameWithoutOrientation(current, desired); return sameBlockstate(current, desired);
} }
public class BuilderCalculationContext extends CalculationContext { public class BuilderCalculationContext extends CalculationContext {

View File

@ -28,6 +28,7 @@ import baritone.cache.CachedChunk;
import baritone.cache.WorldScanner; import baritone.cache.WorldScanner;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.precompute.PrecomputedData;
import baritone.utils.BaritoneProcessHelper; import baritone.utils.BaritoneProcessHelper;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block; import net.minecraft.block.Block;
@ -102,11 +103,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
return null; return null;
} }
} }
if (!Baritone.settings().allowBreak.value) {
logDirect("Unable to mine when allowBreak is false!");
cancel();
return null;
}
updateLoucaSystem(); updateLoucaSystem();
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value; int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.value;
List<BlockPos> curr = new ArrayList<>(knownOreLocations); List<BlockPos> curr = new ArrayList<>(knownOreLocations);
@ -115,7 +112,10 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
Baritone.getExecutor().execute(() -> rescan(curr, context)); Baritone.getExecutor().execute(() -> rescan(curr, context));
} }
if (Baritone.settings().legitMine.value) { if (Baritone.settings().legitMine.value) {
addNearby(); if (!addNearby()) {
cancel();
return null;
}
} }
Optional<BlockPos> shaft = curr.stream() Optional<BlockPos> shaft = curr.stream()
.filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ()) .filter(pos -> pos.getX() == ctx.playerFeet().getX() && pos.getZ() == ctx.playerFeet().getZ())
@ -176,6 +176,11 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
} }
private PathingCommand updateGoal() { private PathingCommand updateGoal() {
BlockOptionalMetaLookup filter = filterFilter();
if (filter == null) {
return null;
}
boolean legit = Baritone.settings().legitMine.value; boolean legit = Baritone.settings().legitMine.value;
List<BlockPos> locs = knownOreLocations; List<BlockPos> locs = knownOreLocations;
if (!locs.isEmpty()) { if (!locs.isEmpty()) {
@ -220,6 +225,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
} }
private void rescan(List<BlockPos> already, CalculationContext context) { private void rescan(List<BlockPos> already, CalculationContext context) {
BlockOptionalMetaLookup filter = filterFilter();
if (filter == null) { if (filter == null) {
return; return;
} }
@ -369,11 +375,18 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
return prune(ctx, locs, filter, max, blacklist, dropped); return prune(ctx, locs, filter, max, blacklist, dropped);
} }
private void addNearby() { private boolean addNearby() {
List<BlockPos> dropped = droppedItemsScan(); List<BlockPos> dropped = droppedItemsScan();
knownOreLocations.addAll(dropped); knownOreLocations.addAll(dropped);
BlockPos playerFeet = ctx.playerFeet(); BlockPos playerFeet = ctx.playerFeet();
BlockStateInterface bsi = new BlockStateInterface(ctx); BlockStateInterface bsi = new BlockStateInterface(ctx);
BlockOptionalMetaLookup filter = filterFilter();
if (filter == null) {
return false;
}
int searchDist = 10; int searchDist = 10;
double fakedBlockReachDistance = 20; // at least 10 * sqrt(3) with some extra space to account for positioning within the block double fakedBlockReachDistance = 20; // at least 10 * sqrt(3) with some extra space to account for positioning within the block
for (int x = playerFeet.getX() - searchDist; x <= playerFeet.getX() + searchDist; x++) { for (int x = playerFeet.getX() - searchDist; x <= playerFeet.getX() + searchDist; x++) {
@ -391,6 +404,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
} }
} }
knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist, dropped); knownOreLocations = prune(new CalculationContext(baritone), knownOreLocations, filter, ORE_LOCATIONS_COUNT, blacklist, dropped);
return true;
} }
private static List<BlockPos> prune(CalculationContext ctx, List<BlockPos> locs2, BlockOptionalMetaLookup filter, int max, List<BlockPos> blacklist, List<BlockPos> dropped) { private static List<BlockPos> prune(CalculationContext ctx, List<BlockPos> locs2, BlockOptionalMetaLookup filter, int max, List<BlockPos> blacklist, List<BlockPos> dropped) {
@ -466,10 +480,8 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
@Override @Override
public void mine(int quantity, BlockOptionalMetaLookup filter) { public void mine(int quantity, BlockOptionalMetaLookup filter) {
this.filter = filter; this.filter = filter;
if (filter != null && !Baritone.settings().allowBreak.value) { if (this.filterFilter() == null) {
logDirect("Unable to mine when allowBreak is false!"); this.filter = null;
this.mine(quantity, (BlockOptionalMetaLookup) null);
return;
} }
this.desiredQuantity = quantity; this.desiredQuantity = quantity;
this.knownOreLocations = new ArrayList<>(); this.knownOreLocations = new ArrayList<>();
@ -481,4 +493,22 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
rescan(new ArrayList<>(), new CalculationContext(baritone)); rescan(new ArrayList<>(), new CalculationContext(baritone));
} }
} }
private BlockOptionalMetaLookup filterFilter() {
if (this.filter == null) {
return null;
}
if (!Baritone.settings().allowBreak.value) {
BlockOptionalMetaLookup f = new BlockOptionalMetaLookup(this.filter.blocks()
.stream()
.filter(e -> Baritone.settings().allowBreakAnyway.value.contains(e.getBlock()))
.toArray(BlockOptionalMeta[]::new));
if (f.blocks().isEmpty()) {
logDirect("Unable to mine when allowBreak is false and target block is not in allowBreakAnyway!");
return null;
}
return f;
}
return filter;
}
} }

View File

@ -0,0 +1,27 @@
/*
* 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.utils.accessor;
/**
* @author rycbar
* @since 26.09.2022
*/
public interface INBTTagLongArray {
long[] getLongArray();
}

View File

@ -19,6 +19,7 @@ package baritone.utils.schematic.format;
import baritone.api.schematic.IStaticSchematic; import baritone.api.schematic.IStaticSchematic;
import baritone.api.schematic.format.ISchematicFormat; import baritone.api.schematic.format.ISchematicFormat;
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import baritone.utils.schematic.format.defaults.MCEditSchematic; import baritone.utils.schematic.format.defaults.MCEditSchematic;
import baritone.utils.schematic.format.defaults.SpongeSchematic; import baritone.utils.schematic.format.defaults.SpongeSchematic;
import net.minecraft.nbt.CompressedStreamTools; import net.minecraft.nbt.CompressedStreamTools;
@ -65,6 +66,26 @@ public enum DefaultSchematicFormats implements ISchematicFormat {
throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic"); throw new UnsupportedOperationException("Unsupported Version of a Sponge Schematic");
} }
} }
},
/**
* The Litematica schematic specification. Commonly denoted by the ".litematic" file extension.
*/
LITEMATICA("litematic") {
@Override
public IStaticSchematic parse(InputStream input) throws IOException {
NBTTagCompound nbt = CompressedStreamTools.readCompressed(input);
int version = nbt.getInteger("Version");
switch (version) {
case 4: //1.12
return new LitematicaSchematic(nbt, false);
case 5: //1.13-1.17
case 6: //1.18+
throw new UnsupportedOperationException("This litematic Verion is too new.");
default:
throw new UnsupportedOperationException("Unsuported Version of a Litematica Schematic");
}
}
}; };
private final String extension; private final String extension;

View File

@ -0,0 +1,347 @@
/*
* 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.utils.schematic.format.defaults;
import baritone.utils.accessor.INBTTagLongArray;
import baritone.utils.schematic.StaticSchematic;
import net.minecraft.block.Block;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.Vec3i;
import org.apache.commons.lang3.Validate;
import javax.annotation.Nullable;
import java.util.Optional;
/**
* Based on EmersonDove's work
* <a href="https://github.com/cabaletta/baritone/pull/2544">...</a>
*
* @author rycbar
* @since 22.09.2022
*/
public final class LitematicaSchematic extends StaticSchematic {
private final Vec3i offsetMinCorner;
private final NBTTagCompound nbt;
/**
* @param nbtTagCompound a decompressed file stream aka nbt data.
* @param rotated if the schematic is rotated by 90°.
*/
public LitematicaSchematic(NBTTagCompound nbtTagCompound, boolean rotated) {
this.nbt = nbtTagCompound;
this.offsetMinCorner = new Vec3i(getMinOfSchematic("x"), getMinOfSchematic("y"), getMinOfSchematic("z"));
this.y = Math.abs(nbt.getCompoundTag("Metadata").getCompoundTag("EnclosingSize").getInteger("y"));
if (rotated) {
this.x = Math.abs(nbt.getCompoundTag("Metadata").getCompoundTag("EnclosingSize").getInteger("z"));
this.z = Math.abs(nbt.getCompoundTag("Metadata").getCompoundTag("EnclosingSize").getInteger("x"));
} else {
this.x = Math.abs(nbt.getCompoundTag("Metadata").getCompoundTag("EnclosingSize").getInteger("x"));
this.z = Math.abs(nbt.getCompoundTag("Metadata").getCompoundTag("EnclosingSize").getInteger("z"));
}
this.states = new IBlockState[this.x][this.z][this.y];
fillInSchematic();
}
/**
* @return Array of subregion names.
*/
private static String[] getRegions(NBTTagCompound nbt) {
return nbt.getCompoundTag("Regions").getKeySet().toArray(new String[0]);
}
/**
* Gets both ends from a region box for a given axis and returns the lower one.
*
* @param s axis that should be read.
* @return the lower coord of the requested axis.
*/
private static int getMinOfSubregion(NBTTagCompound nbt, String subReg, String s) {
int a = nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Position").getInteger(s);
int b = nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger(s);
if (b < 0) {
b++;
}
return Math.min(a, a + b);
}
/**
* @param blockStatePalette List of all different block types used in the schematic.
* @return Array of BlockStates.
*/
private static IBlockState[] getBlockList(NBTTagList blockStatePalette) {
IBlockState[] blockList = new IBlockState[blockStatePalette.tagCount()];
for (int i = 0; i < blockStatePalette.tagCount(); i++) {
Block block = Block.REGISTRY.getObject(new ResourceLocation((((NBTTagCompound) blockStatePalette.get(i)).getString("Name"))));
NBTTagCompound properties = ((NBTTagCompound) blockStatePalette.get(i)).getCompoundTag("Properties");
blockList[i] = getBlockState(block, properties);
}
return blockList;
}
/**
* @param block block.
* @param properties List of Properties the block has.
* @return A blockState.
*/
private static IBlockState getBlockState(Block block, NBTTagCompound properties) {
IBlockState blockState = block.getDefaultState();
for (Object key : properties.getKeySet().toArray()) {
IProperty<?> property = block.getBlockState().getProperty((String) key);
String propertyValue = properties.getString((String) key);
if (property != null) {
blockState = setPropertyValue(blockState, property, propertyValue);
}
}
return blockState;
}
/**
* @author Emerson
*/
private static <T extends Comparable<T>> IBlockState setPropertyValue(IBlockState state, IProperty<T> property, String value) {
Optional<T> parsed = property.parseValue(value).toJavaUtil();
if (parsed.isPresent()) {
return state.withProperty(property, parsed.get());
} else {
throw new IllegalArgumentException("Invalid value for property " + property);
}
}
/**
* @param amountOfBlockTypes amount of block types in the schematic.
* @return amount of bits used to encode a block.
*/
private static int getBitsPerBlock(int amountOfBlockTypes) {
return (int) Math.max(2,Math.ceil(Math.log(amountOfBlockTypes) / Math.log(2)));
}
/**
* Calculates the volume of the subregion. As size can be a negative value we take the absolute value of the
* multiplication as the volume still holds a positive amount of blocks.
*
* @return the volume of the subregion.
*/
private static long getVolume(NBTTagCompound nbt, String subReg) {
return Math.abs(
nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("x") *
nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("y") *
nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("z"));
}
/**
* @return array of Long values.
*/
private static long[] getBlockStates(NBTTagCompound nbt, String subReg) {
return ((INBTTagLongArray) nbt.getCompoundTag("Regions").getCompoundTag(subReg).getTag("BlockStates")).getLongArray();
}
/**
* Subregion don't have to be the same size as the enclosing size of the schematic. If they are smaller we check here if the current block is part of the subregion.
*
* @param x coord of the block relative to the minimum corner.
* @param y coord of the block relative to the minimum corner.
* @param z coord of the block relative to the minimum corner.
* @return if the current block is part of the subregion.
*/
private static boolean inSubregion(NBTTagCompound nbt, String subReg, int x, int y, int z) {
return x >= 0 && y >= 0 && z >= 0 &&
x < Math.abs(nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("x")) &&
y < Math.abs(nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("y")) &&
z < Math.abs(nbt.getCompoundTag("Regions").getCompoundTag(subReg).getCompoundTag("Size").getInteger("z"));
}
/**
* @param s axis.
* @return the lowest coordinate of that axis of the schematic.
*/
private int getMinOfSchematic(String s) {
int n = Integer.MAX_VALUE;
for (String subReg : getRegions(nbt)) {
n = Math.min(n, getMinOfSubregion(nbt, subReg, s));
}
return n;
}
/**
* reads the file data.
*/
private void fillInSchematic() {
for (String subReg : getRegions(nbt)) {
NBTTagList usedBlockTypes = nbt.getCompoundTag("Regions").getCompoundTag(subReg).getTagList("BlockStatePalette", 10);
IBlockState[] blockList = getBlockList(usedBlockTypes);
int bitsPerBlock = getBitsPerBlock(usedBlockTypes.tagCount());
long regionVolume = getVolume(nbt, subReg);
long[] blockStateArray = getBlockStates(nbt, subReg);
LitematicaBitArray bitArray = new LitematicaBitArray(bitsPerBlock, regionVolume, blockStateArray);
writeSubregionIntoSchematic(nbt, subReg, blockList, bitArray);
}
}
/**
* Writes the file data in to the IBlockstate array.
*
* @param blockList list with the different block types used in the schematic.
* @param bitArray bit array that holds the placement pattern.
*/
private void writeSubregionIntoSchematic(NBTTagCompound nbt, String subReg, IBlockState[] blockList, LitematicaBitArray bitArray) {
Vec3i offsetSubregion = new Vec3i(getMinOfSubregion(nbt, subReg, "x"), getMinOfSubregion(nbt, subReg, "y"), getMinOfSubregion(nbt, subReg, "z"));
int index = 0;
for (int y = 0; y < this.y; y++) {
for (int z = 0; z < this.z; z++) {
for (int x = 0; x < this.x; x++) {
if (inSubregion(nbt, subReg, x, y, z)) {
this.states[x - (offsetMinCorner.getX() - offsetSubregion.getX())][z - (offsetMinCorner.getZ() - offsetSubregion.getZ())][y - (offsetMinCorner.getY() - offsetSubregion.getY())] = blockList[bitArray.getAt(index)];
index++;
}
}
}
}
}
/**
* @return offset from the schematic origin to the minimum Corner as a Vec3i.
*/
public Vec3i getOffsetMinCorner() {
return offsetMinCorner;
}
/**
* @return x size of the schematic.
*/
public int getX() {
return this.x;
}
/**
* @return y size of the schematic.
*/
public int getY() {
return this.y;
}
/**
* @return z size of the schematic.
*/
public int getZ() {
return this.z;
}
/**
* @param x position relative to the minimum corner of the schematic.
* @param y position relative to the minimum corner of the schematic.
* @param z position relative to the minimum corner of the schematic.
* @param blockState new blockstate of the block at this position.
*/
public void setDirect(int x, int y, int z, IBlockState blockState) {
this.states[x][z][y] = blockState;
}
/**
* @param rotated if the schematic is rotated by 90°.
* @return a copy of the schematic.
*/
public LitematicaSchematic getCopy(boolean rotated) {
return new LitematicaSchematic(nbt, rotated);
}
/**
* @author maruohon
* Class from the Litematica mod by maruohon
* Usage under LGPLv3 with the permission of the author.
* <a href="https://github.com/maruohon/litematica">...</a>
*/
private static class LitematicaBitArray {
/**
* The long array that is used to store the data for this BitArray.
*/
private final long[] longArray;
/**
* Number of bits a single entry takes up
*/
private final int bitsPerEntry;
/**
* The maximum value for a single entry. This also works as a bitmask for a single entry.
* For instance, if bitsPerEntry were 5, this value would be 31 (ie, {@code 0b00011111}).
*/
private final long maxEntryValue;
/**
* Number of entries in this array (<b>not</b> the length of the long array that internally backs this array)
*/
private final long arraySize;
public LitematicaBitArray(int bitsPerEntryIn, long arraySizeIn, @Nullable long[] longArrayIn) {
Validate.inclusiveBetween(1L, 32L, bitsPerEntryIn);
this.arraySize = arraySizeIn;
this.bitsPerEntry = bitsPerEntryIn;
this.maxEntryValue = (1L << bitsPerEntryIn) - 1L;
if (longArrayIn != null) {
this.longArray = longArrayIn;
} else {
this.longArray = new long[(int) (roundUp(arraySizeIn * (long) bitsPerEntryIn, 64L) / 64L)];
}
}
public static long roundUp(long number, long interval) {
int sign = 1;
if (interval == 0) {
return 0;
} else if (number == 0) {
return interval;
} else {
if (number < 0) {
sign = -1;
}
long i = number % (interval * sign);
return i == 0 ? number : number + (interval * sign) - i;
}
}
public int getAt(long index) {
Validate.inclusiveBetween(0L, this.arraySize - 1L, index);
long startOffset = index * (long) this.bitsPerEntry;
int startArrIndex = (int) (startOffset >> 6); // startOffset / 64
int endArrIndex = (int) (((index + 1L) * (long) this.bitsPerEntry - 1L) >> 6);
int startBitOffset = (int) (startOffset & 0x3F); // startOffset % 64
if (startArrIndex == endArrIndex) {
return (int) (this.longArray[startArrIndex] >>> startBitOffset & this.maxEntryValue);
} else {
int endOffset = 64 - startBitOffset;
return (int) ((this.longArray[startArrIndex] >>> startBitOffset | this.longArray[endArrIndex] << endOffset) & this.maxEntryValue);
}
}
public long size() {
return this.arraySize;
}
}
}

View File

@ -0,0 +1,215 @@
/*
* 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.utils.schematic.litematica;
import baritone.utils.schematic.format.defaults.LitematicaSchematic;
import fi.dy.masa.litematica.Litematica;
import fi.dy.masa.litematica.data.DataManager;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
import net.minecraft.util.math.Vec3i;
import java.io.File;
/**
* Helper class that provides access or processes data related to Litmatica schematics.
*
* @author rycbar
* @since 28.09.2022
*/
public final class LitematicaHelper {
/**
* @return if Litmatica is installed.
*/
public static boolean isLitematicaPresent() {
try {
Class.forName(Litematica.class.getName());
return true;
} catch (ClassNotFoundException | NoClassDefFoundError ex) {
return false;
}
}
/**
* @return if there are loaded schematics.
*/
public static boolean hasLoadedSchematic() {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().size() > 0;
}
/**
* @param i index of the Schematic in the schematic placement list.
* @return the name of the requested schematic.
*/
public static String getName(int i) {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getName();
}
/**
* @param i index of the Schematic in the schematic placement list.
* @return the world coordinates of the schematic origin. This can but does not have to be the minimum corner.
*/
public static Vec3i getOrigin(int i) {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getOrigin();
}
/**
* @param i index of the Schematic in the schematic placement list.
* @return Filepath of the schematic file.
*/
public static File getSchematicFile(int i) {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getSchematicFile();
}
/**
* @param i index of the Schematic in the schematic placement list.
* @return rotation of the schematic placement.
*/
public static Rotation getRotation(int i) {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getRotation();
}
/**
* @param i index of the Schematic in the schematic placement list.
* @return the mirroring of the schematic placement.
*/
public static Mirror getMirror(int i) {
return DataManager.getSchematicPlacementManager().getAllSchematicsPlacements().get(i).getMirror();
}
/**
* @param schematic original schematic.
* @param i index of the Schematic in the schematic placement list.
* @return the minimum corner coordinates of the schematic, after the original schematic got rotated and mirrored.
*/
public static Vec3i getCorrectedOrigin(LitematicaSchematic schematic, int i) {
int x = LitematicaHelper.getOrigin(i).getX();
int y = LitematicaHelper.getOrigin(i).getY();
int z = LitematicaHelper.getOrigin(i).getZ();
int mx = schematic.getOffsetMinCorner().getX();
int my = schematic.getOffsetMinCorner().getY();
int mz = schematic.getOffsetMinCorner().getZ();
int sx = (schematic.getX() - 1) * -1;
int sz = (schematic.getZ() - 1) * -1;
Vec3i correctedOrigin;
Mirror mirror = LitematicaHelper.getMirror(i);
Rotation rotation = LitematicaHelper.getRotation(i);
//todo there has to be a better way to do this but i cant finde it atm
switch (mirror) {
case FRONT_BACK:
case LEFT_RIGHT:
switch ((mirror.ordinal() * 2 + rotation.ordinal()) % 4) {
case 1:
correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + (sx - mx));
break;
case 2:
correctedOrigin = new Vec3i(x + mx, y + my, z + (sz - mz));
break;
case 3:
correctedOrigin = new Vec3i(x + mz, y + my, z + mx);
break;
default:
correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + mz);
break;
}
break;
default:
switch (rotation) {
case CLOCKWISE_90:
correctedOrigin = new Vec3i(x + (sz - mz), y + my, z + mx);
break;
case CLOCKWISE_180:
correctedOrigin = new Vec3i(x + (sx - mx), y + my, z + (sz - mz));
break;
case COUNTERCLOCKWISE_90:
correctedOrigin = new Vec3i(x + mz, y + my, z + (sx - mx));
break;
default:
correctedOrigin = new Vec3i(x + mx, y + my, z + mz);
break;
}
}
return correctedOrigin;
}
/**
* @param in the xyz offsets of the block relative to the schematic minimum corner.
* @param sizeX size of the schematic in the x-axis direction.
* @param sizeZ size of the schematic in the z-axis direction.
* @param mirror the mirroring of the schematic placement.
* @return the corresponding xyz coordinates after mirroring them according to the given mirroring.
*/
public static Vec3i doMirroring(Vec3i in, int sizeX, int sizeZ, Mirror mirror) {
int xOut = in.getX();
int zOut = in.getZ();
if (mirror == Mirror.LEFT_RIGHT) {
zOut = sizeZ - in.getZ();
} else if (mirror == Mirror.FRONT_BACK) {
xOut = sizeX - in.getX();
}
return new Vec3i(xOut, in.getY(), zOut);
}
/**
* @param in the xyz offsets of the block relative to the schematic minimum corner.
* @param sizeX size of the schematic in the x-axis direction.
* @param sizeZ size of the schematic in the z-axis direction.
* @return the corresponding xyz coordinates after rotation them 90° clockwise.
*/
public static Vec3i rotate(Vec3i in, int sizeX, int sizeZ) {
return new Vec3i(sizeX - (sizeX - sizeZ) - in.getZ(), in.getY(), in.getX());
}
/**
* IDFK this just grew and it somehow works. If you understand how, pls tell me.
*
* @param schemIn give in the original schematic.
* @param i index of the Schematic in the schematic placement list.
* @return get it out rotated and mirrored.
*/
public static LitematicaSchematic blackMagicFuckery(LitematicaSchematic schemIn, int i) {
LitematicaSchematic tempSchem = schemIn.getCopy(LitematicaHelper.getRotation(i).ordinal() % 2 == 1);
for (int yCounter = 0; yCounter < schemIn.getY(); yCounter++) {
for (int zCounter = 0; zCounter < schemIn.getZ(); zCounter++) {
for (int xCounter = 0; xCounter < schemIn.getX(); xCounter++) {
Vec3i xyzHolder = new Vec3i(xCounter, yCounter, zCounter);
xyzHolder = LitematicaHelper.doMirroring(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1, LitematicaHelper.getMirror(i));
for (int turns = 0; turns < LitematicaHelper.getRotation(i).ordinal(); turns++) {
if ((turns % 2) == 0) {
xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getX() - 1, schemIn.getZ() - 1);
} else {
xyzHolder = LitematicaHelper.rotate(xyzHolder, schemIn.getZ() - 1, schemIn.getX() - 1);
}
}
IBlockState state = schemIn.getDirect(xCounter, yCounter, zCounter);
try {
state = state.withMirror(LitematicaHelper.getMirror(i)).withRotation(LitematicaHelper.getRotation(i));
} catch (NullPointerException e) {
//nothing to worry about it's just a hole in the schematic.
}
tempSchem.setDirect(xyzHolder.getX(), xyzHolder.getY(), xyzHolder.getZ(), state);
}
}
}
return tempSchem;
}
}

View File

@ -0,0 +1,21 @@
/*
* 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 fi.dy.masa.litematica;
public class Litematica {
}

View File

@ -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 fi.dy.masa.litematica.data;
import fi.dy.masa.litematica.schematic.placement.SchematicPlacementManager;
public class DataManager {
public static final DataManager INSTANCE = new DataManager();
private final SchematicPlacementManager schematicPlacementManager = new SchematicPlacementManager();
private static DataManager getInstance() {
return INSTANCE;
}
public static SchematicPlacementManager getSchematicPlacementManager() {
return getInstance().schematicPlacementManager;
}
}

View File

@ -0,0 +1,35 @@
/*
* 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 fi.dy.masa.litematica.schematic.placement;
import net.minecraft.util.Mirror;
import net.minecraft.util.Rotation;
public class SchematicPlacement extends SchematicPlacementUnloaded {
private Rotation rotation;
private Mirror mirror;
public Rotation getRotation() {
return this.rotation;
}
public Mirror getMirror() {
return this.mirror;
}
}

View File

@ -0,0 +1,31 @@
/*
* 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 fi.dy.masa.litematica.schematic.placement;
import java.util.ArrayList;
import java.util.List;
public class SchematicPlacementManager {
private final List<SchematicPlacement> schematicPlacements = new ArrayList<>();
//in case of a java.lang.NoSuchMethodError try change the name of this method to getAllSchematicPlacements()
//there are inconsistencies in the litematica mod about the naming of this method
public List<SchematicPlacement> getAllSchematicsPlacements() {
return schematicPlacements;
}
}

View File

@ -0,0 +1,43 @@
/*
* 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 fi.dy.masa.litematica.schematic.placement;
import net.minecraft.util.math.BlockPos;
import javax.annotation.Nullable;
import java.io.File;
public class SchematicPlacementUnloaded {
protected String name = "?";
@Nullable
protected File schematicFile;
protected BlockPos origin = BlockPos.ORIGIN;
public String getName() {
return this.name;
}
@Nullable
public File getSchematicFile() {
return this.schematicFile;
}
public BlockPos getOrigin() {
return this.origin;
}
}