Merge branch 'master' into mapping

This commit is contained in:
Howard Stark
2018-08-26 23:32:12 -07:00
50 changed files with 1662 additions and 440 deletions
+8 -1
View File
@@ -1,3 +1,10 @@
# Baritone # Baritone
A Minecraft bot. This project is an updated version of [Minebot](https://github.com/leijurv/MineBot/), A Minecraft bot. This project is an updated version of [Minebot](https://github.com/leijurv/MineBot/),
the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2.
# Setup
- Open the project in IntelliJ as a Gradle project
- Run the Gradle task `setupDecompWorkspace`
- Run the Gradle task `genIntellijRuns`
- Restart IntelliJ and import Gradle changes
- Select the "Minecraft Client" launch config and run
+6 -1
View File
@@ -16,7 +16,7 @@
*/ */
group 'baritone' group 'baritone'
version '1.0' version '1.0.0'
buildscript { buildscript {
repositories { repositories {
@@ -75,3 +75,8 @@ dependencies {
} }
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
} }
mixin {
defaultObfuscationEnv notch
add sourceSets.main, 'mixins.baritone.refmap.json'
}
+2
View File
@@ -21,6 +21,7 @@ import baritone.behavior.Behavior;
import baritone.behavior.impl.LookBehavior; import baritone.behavior.impl.LookBehavior;
import baritone.behavior.impl.MemoryBehavior; import baritone.behavior.impl.MemoryBehavior;
import baritone.behavior.impl.PathingBehavior; import baritone.behavior.impl.PathingBehavior;
import baritone.behavior.impl.LocationTrackingBehavior;
import baritone.event.GameEventHandler; import baritone.event.GameEventHandler;
import baritone.map.Map; import baritone.map.Map;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
@@ -72,6 +73,7 @@ public enum Baritone {
registerBehavior(LookBehavior.INSTANCE); registerBehavior(LookBehavior.INSTANCE);
registerBehavior(MemoryBehavior.INSTANCE); registerBehavior(MemoryBehavior.INSTANCE);
registerBehavior(Map.INSTANCE); registerBehavior(Map.INSTANCE);
registerBehavior(LocationTrackingBehavior.INSTANCE);
} }
this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone"); this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");
+34 -1
View File
@@ -107,12 +107,25 @@ public class Settings {
*/ */
public Setting<Boolean> minimumImprovementRepropagation = new Setting<>(true); public Setting<Boolean> minimumImprovementRepropagation = new Setting<>(true);
/**
* Use a pythagorean metric (as opposed to the more accurate hybrid diagonal / traverse).
* You probably don't want this. It roughly triples nodes considered for no real advantage.
*/
public Setting<Boolean> pythagoreanMetric = new Setting<>(false);
/** /**
* After calculating a path (potentially through cached chunks), artificially cut it off to just the part that is * After calculating a path (potentially through cached chunks), artificially cut it off to just the part that is
* entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified. * entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified.
*/ */
public Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(true); public Setting<Boolean> cutoffAtLoadBoundary = new Setting<>(true);
/**
* Stop 5 movements before anything that made the path COST_INF.
* For example, if lava has spread across the path, don't walk right up to it then recalculate, it might
* still be spreading lol
*/
public Setting<Integer> costVerificationLookahead = new Setting<>(5);
/** /**
* Static cutoff factor. 0.9 means cut off the last 10% of all paths, regardless of chunk load state * Static cutoff factor. 0.9 means cut off the last 10% of all paths, regardless of chunk load state
*/ */
@@ -141,6 +154,13 @@ public class Settings {
*/ */
public Setting<Integer> maxFallHeightBucket = new Setting<>(20); public Setting<Integer> maxFallHeightBucket = new Setting<>(20);
/**
* Is it okay to sprint through a descend followed by a diagonal?
* The player overshoots the landing, but not enough to fall off. And the diagonal ensures that there isn't
* lava or anything that's !canWalkInto in that space, so it's technically safe, just a little sketchy.
*/
public Setting<Boolean> allowOvershootDiagonalDescend = new Setting<>(true);
/** /**
* If your goal is a GoalBlock in an unloaded chunk, assume it's far enough away that the Y coord * If your goal is a GoalBlock in an unloaded chunk, assume it's far enough away that the Y coord
* doesn't matter yet, and replace it with a GoalXZ to the same place before calculating a path. * doesn't matter yet, and replace it with a GoalXZ to the same place before calculating a path.
@@ -222,11 +242,24 @@ public class Settings {
*/ */
public Setting<Boolean> freeLook = new Setting<>(true); public Setting<Boolean> freeLook = new Setting<>(true);
/**
* Will cause some minor behavioral differences to ensure that Baritone works on anticheats.
* <p>
* At the moment this will silently set the player's rotations when using freeLook so you're not sprinting in
* directions other than forward, which is picken up by more "advanced" anticheats like AAC, but not NCP.
*/
public Setting<Boolean> antiCheatCompatibility = new Setting<>(true);
/** /**
* Exclusively use cached chunks for pathing * Exclusively use cached chunks for pathing
*/ */
public Setting<Boolean> pathThroughCachedOnly = new Setting<>(false); public Setting<Boolean> pathThroughCachedOnly = new Setting<>(false);
/**
* Whether or not to use the "#" command prefix
*/
public Setting<Boolean> prefix = new Setting<>(false);
public final Map<String, Setting<?>> byLowerName; public final Map<String, Setting<?>> byLowerName;
public final List<Setting<?>> allSettings; public final List<Setting<?>> allSettings;
@@ -291,7 +324,7 @@ public class Settings {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> List<Setting<T>> getByValueType(Class<T> klass) { public <T> List<Setting<T>> getByValueType(Class<T> klass) {
ArrayList<Setting<T>> result = new ArrayList<>(); List<Setting<T>> result = new ArrayList<>();
for (Setting<?> setting : allSettings) { for (Setting<?> setting : allSettings) {
if (setting.klass.equals(klass)) { if (setting.klass.equals(klass)) {
result.add((Setting<T>) setting); result.add((Setting<T>) setting);
@@ -0,0 +1,53 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.behavior.impl;
import baritone.behavior.Behavior;
import baritone.chunk.Waypoint;
import baritone.chunk.WorldProvider;
import baritone.event.events.BlockInteractEvent;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.BlockBed;
/**
* A collection of event methods that are used to interact with Baritone's
* waypoint system. This class probably needs a better name.
*
* @see Waypoint
*
* @author Brady
* @since 8/22/2018
*/
public final class LocationTrackingBehavior extends Behavior {
public static final LocationTrackingBehavior INSTANCE = new LocationTrackingBehavior();
private LocationTrackingBehavior() {}
@Override
public void onBlockInteract(BlockInteractEvent event) {
if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(event.getPos()) instanceof BlockBed) {
WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos()));
}
}
@Override
public void onPlayerDeath() {
WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet()));
}
}
@@ -58,21 +58,42 @@ public class LookBehavior extends Behavior {
@Override @Override
public void onPlayerUpdate(PlayerUpdateEvent event) { public void onPlayerUpdate(PlayerUpdateEvent event) {
if (event.getState() == EventState.PRE && this.target != null && this.force) { if (this.target == null)
player().rotationYaw = this.target.getFirst(); return;
float oldPitch = player().rotationPitch;
float desiredPitch = this.target.getSecond(); // Whether or not we're going to silently set our angles
player().rotationPitch = desiredPitch; boolean silent = Baritone.settings().antiCheatCompatibility.get();
if (desiredPitch == oldPitch) {
nudgeToLevel(); switch (event.getState()) {
case PRE: {
if (this.force) {
player().rotationYaw = this.target.getFirst();
float oldPitch = player().rotationPitch;
float desiredPitch = this.target.getSecond();
player().rotationPitch = desiredPitch;
if (desiredPitch == oldPitch) {
nudgeToLevel();
}
this.target = null;
} else if (silent) {
this.lastYaw = player().rotationYaw;
player().rotationYaw = this.target.getFirst();
}
break;
}
case POST: {
if (!this.force && silent) {
player().rotationYaw = this.lastYaw;
this.target = null;
}
break;
} }
this.target = null;
} }
} }
@Override @Override
public void onPlayerRelativeMove(RelativeMoveEvent event) { public void onPlayerRelativeMove(RelativeMoveEvent event) {
if (this.target != null && !force) { if (this.target != null && !this.force) {
switch (event.getState()) { switch (event.getState()) {
case PRE: case PRE:
this.lastYaw = player().rotationYaw; this.lastYaw = player().rotationYaw;
@@ -80,7 +101,10 @@ public class LookBehavior extends Behavior {
break; break;
case POST: case POST:
player().rotationYaw = this.lastYaw; player().rotationYaw = this.lastYaw;
this.target = null;
// If we have antiCheatCompatibility on, we're going to use the target value later in onPlayerUpdate()
if (!Baritone.settings().antiCheatCompatibility.get())
this.target = null;
break; break;
} }
} }
@@ -19,6 +19,7 @@ package baritone.behavior.impl;
import baritone.Baritone; import baritone.Baritone;
import baritone.behavior.Behavior; import baritone.behavior.Behavior;
import baritone.event.events.PathEvent;
import baritone.event.events.PlayerUpdateEvent; import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.RenderEvent; import baritone.event.events.RenderEvent;
import baritone.event.events.TickEvent; import baritone.event.events.TickEvent;
@@ -59,6 +60,10 @@ public class PathingBehavior extends Behavior {
private boolean lastAutoJump; private boolean lastAutoJump;
private void dispatchPathEvent(PathEvent event) {
new Thread(() -> Baritone.INSTANCE.getGameEventHandler().onPathEvent(event)).start();
}
@Override @Override
public void onTick(TickEvent event) { public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) { if (event.getType() == TickEvent.Type.OUT) {
@@ -74,6 +79,7 @@ public class PathingBehavior extends Behavior {
current = null; current = null;
if (goal == null || goal.isInGoal(playerFeet())) { if (goal == null || goal.isInGoal(playerFeet())) {
displayChatMessageRaw("All done. At " + goal); displayChatMessageRaw("All done. At " + goal);
dispatchPathEvent(PathEvent.AT_GOAL);
next = null; next = null;
return; return;
} }
@@ -85,10 +91,12 @@ public class PathingBehavior extends Behavior {
// but if we fail in the middle of current // but if we fail in the middle of current
// we're nowhere close to our planned ahead path // we're nowhere close to our planned ahead path
// so need to discard it sadly. // so need to discard it sadly.
dispatchPathEvent(PathEvent.DISCARD_NEXT);
next = null; next = null;
} }
if (next != null) { if (next != null) {
displayChatMessageRaw("Continuing on to planned next path"); displayChatMessageRaw("Continuing on to planned next path");
dispatchPathEvent(PathEvent.CONTINUING_ONTO_PLANNED_NEXT);
current = next; current = next;
next = null; next = null;
return; return;
@@ -96,9 +104,11 @@ public class PathingBehavior extends Behavior {
// at this point, current just ended, but we aren't in the goal and have no plan for the future // at this point, current just ended, but we aren't in the goal and have no plan for the future
synchronized (pathCalcLock) { synchronized (pathCalcLock) {
if (isPathCalcInProgress) { if (isPathCalcInProgress) {
dispatchPathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING);
// if we aren't calculating right now // if we aren't calculating right now
return; return;
} }
dispatchPathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true, Optional.empty()); findPathInNewThread(pathStart(), true, Optional.empty());
} }
return; return;
@@ -110,6 +120,7 @@ public class PathingBehavior extends Behavior {
if (next.getPath().positions().contains(playerFeet())) { if (next.getPath().positions().contains(playerFeet())) {
// jump directly onto the next path // jump directly onto the next path
displayChatMessageRaw("Splicing into planned next path early..."); displayChatMessageRaw("Splicing into planned next path early...");
dispatchPathEvent(PathEvent.SPLICING_ONTO_NEXT_EARLY);
current = next; current = next;
next = null; next = null;
return; return;
@@ -132,6 +143,7 @@ public class PathingBehavior extends Behavior {
if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) { if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) {
// and this path has 5 seconds or less left // and this path has 5 seconds or less left
displayChatMessageRaw("Path almost over. Planning ahead..."); displayChatMessageRaw("Path almost over. Planning ahead...");
dispatchPathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED);
findPathInNewThread(current.getPath().getDest(), false, Optional.of(current.getPath())); findPathInNewThread(current.getPath().getDest(), false, Optional.of(current.getPath()));
} }
} }
@@ -164,6 +176,10 @@ public class PathingBehavior extends Behavior {
this.goal = goal; this.goal = goal;
} }
public Goal getGoal() {
return goal;
}
public PathExecutor getCurrent() { public PathExecutor getCurrent() {
return current; return current;
} }
@@ -192,6 +208,7 @@ public class PathingBehavior extends Behavior {
if (isPathCalcInProgress) { if (isPathCalcInProgress) {
return; return;
} }
dispatchPathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true, Optional.empty()); findPathInNewThread(pathStart(), true, Optional.empty());
} }
} }
@@ -227,19 +244,29 @@ public class PathingBehavior extends Behavior {
if (Baritone.settings().cutoffAtLoadBoundary.get()) { if (Baritone.settings().cutoffAtLoadBoundary.get()) {
path = path.map(IPath::cutoffAtLoadedChunks); path = path.map(IPath::cutoffAtLoadedChunks);
} }
path.map(p -> p.staticCutoff(goal)).map(PathExecutor::new).ifPresent(p -> { Optional<PathExecutor> executor = path.map(p -> p.staticCutoff(goal)).map(PathExecutor::new);
synchronized (pathPlanLock) { synchronized (pathPlanLock) {
if (current == null) { if (current == null) {
current = p; if (executor.isPresent()) {
dispatchPathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING);
current = executor.get();
} else { } else {
if (next == null) { dispatchPathEvent(PathEvent.CALC_FAILED);
next = p; }
} else {
if (next == null) {
if (executor.isPresent()) {
dispatchPathEvent(PathEvent.NEXT_SEGMENT_CALC_FINISHED);
next = executor.get();
} else { } else {
throw new IllegalStateException("I have no idea what to do with this path"); dispatchPathEvent(PathEvent.NEXT_CALC_FAILED);
} }
} else {
throw new IllegalStateException("I have no idea what to do with this path");
} }
} }
}); }
if (talkAboutIt && current != null && current.getPath() != null) { if (talkAboutIt && current != null && current.getPath() != null) {
if (goal == null || goal.isInGoal(current.getPath().getDest())) { if (goal == null || goal.isInGoal(current.getPath().getDest())) {
displayChatMessageRaw("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered"); displayChatMessageRaw("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered");
+56 -7
View File
@@ -21,8 +21,10 @@ import baritone.utils.pathing.IBlockTypeAccess;
import baritone.utils.pathing.PathingBlockType; import baritone.utils.pathing.PathingBlockType;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import java.util.BitSet; import java.util.*;
/** /**
* @author Brady * @author Brady
@@ -30,6 +32,39 @@ import java.util.BitSet;
*/ */
public final class CachedChunk implements IBlockTypeAccess { public final class CachedChunk implements IBlockTypeAccess {
public static final Set<Block> BLOCKS_TO_KEEP_TRACK_OF = Collections.unmodifiableSet(new HashSet<Block>() {{
add(Blocks.DIAMOND_ORE);
add(Blocks.DIAMOND_BLOCK);
//add(Blocks.COAL_ORE);
add(Blocks.COAL_BLOCK);
//add(Blocks.IRON_ORE);
add(Blocks.IRON_BLOCK);
//add(Blocks.GOLD_ORE);
add(Blocks.GOLD_BLOCK);
add(Blocks.EMERALD_ORE);
add(Blocks.EMERALD_BLOCK);
add(Blocks.ENDER_CHEST);
add(Blocks.FURNACE);
add(Blocks.CHEST);
add(Blocks.END_PORTAL);
add(Blocks.END_PORTAL_FRAME);
add(Blocks.MOB_SPAWNER);
// TODO add all shulker colors
add(Blocks.PORTAL);
add(Blocks.HOPPER);
add(Blocks.BEACON);
add(Blocks.BREWING_STAND);
add(Blocks.SKULL);
add(Blocks.ENCHANTING_TABLE);
add(Blocks.ANVIL);
add(Blocks.LIT_FURNACE);
add(Blocks.BED);
add(Blocks.DRAGON_EGG);
add(Blocks.JUKEBOX);
add(Blocks.END_GATEWAY);
}});
/** /**
* The size of the chunk data in bits. Equal to 16 KiB. * The size of the chunk data in bits. Equal to 16 KiB.
* <p> * <p>
@@ -66,7 +101,9 @@ public final class CachedChunk implements IBlockTypeAccess {
private final int[] heightMap; private final int[] heightMap;
CachedChunk(int x, int z, BitSet data, String[] overview) { private final Map<String, List<BlockPos>> specialBlockLocations;
CachedChunk(int x, int z, BitSet data, String[] overview, Map<String, List<BlockPos>> specialBlockLocations) {
validateSize(data); validateSize(data);
this.x = x; this.x = x;
@@ -74,6 +111,7 @@ public final class CachedChunk implements IBlockTypeAccess {
this.data = data; this.data = data;
this.overview = overview; this.overview = overview;
this.heightMap = new int[256]; this.heightMap = new int[256];
this.specialBlockLocations = specialBlockLocations;
calculateHeightMap(); calculateHeightMap();
} }
@@ -82,11 +120,7 @@ public final class CachedChunk implements IBlockTypeAccess {
int internalPos = z << 4 | x; int internalPos = z << 4 | x;
if (heightMap[internalPos] == y) { if (heightMap[internalPos] == y) {
// we have this exact block, it's a surface block // we have this exact block, it's a surface block
String name = overview[internalPos]; IBlockState state = ChunkPacker.stringToBlock(overview[internalPos]).getDefaultState();
if (!name.contains(":")) {
name = "minecraft:" + name;
}
IBlockState state = Block.getBlockFromName(name).getDefaultState();
//System.out.println("Saying that " + x + "," + y + "," + z + " is " + state); //System.out.println("Saying that " + x + "," + y + "," + z + " is " + state);
return state; return state;
} }
@@ -118,6 +152,21 @@ public final class CachedChunk implements IBlockTypeAccess {
return overview; return overview;
} }
public final Map<String, List<BlockPos>> getRelativeBlocks() {
return specialBlockLocations;
}
public final LinkedList<BlockPos> getAbsoluteBlocks(String blockType) {
if (specialBlockLocations.get(blockType) == null) {
return null;
}
LinkedList<BlockPos> res = new LinkedList<>();
for (BlockPos pos : specialBlockLocations.get(blockType)) {
res.add(new BlockPos(pos.getX() + x * 16, pos.getY(), pos.getZ() + z * 16));
}
return res;
}
/** /**
* @return Returns the raw packed chunk data as a byte array * @return Returns the raw packed chunk data as a byte array
*/ */
+75 -34
View File
@@ -19,13 +19,13 @@ package baritone.chunk;
import baritone.utils.pathing.IBlockTypeAccess; import baritone.utils.pathing.IBlockTypeAccess;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import java.io.*; import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.BitSet; import java.util.*;
import java.util.function.Consumer;
import java.util.zip.GZIPInputStream; import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream; import java.util.zip.GZIPOutputStream;
@@ -70,34 +70,39 @@ public final class CachedRegion implements IBlockTypeAccess {
@Override @Override
public final IBlockState getBlock(int x, int y, int z) { public final IBlockState getBlock(int x, int y, int z) {
CachedChunk chunk = this.getChunk(x >> 4, z >> 4); CachedChunk chunk = chunks[x >> 4][z >> 4];
if (chunk != null) { if (chunk != null) {
return chunk.getBlock(x & 15, y, z & 15); return chunk.getBlock(x & 15, y, z & 15);
} }
return null; return null;
} }
final void updateCachedChunk(int chunkX, int chunkZ, CachedChunk chunk) { public final LinkedList<BlockPos> getLocationsOf(String block) {
LinkedList<BlockPos> res = new LinkedList<>();
for (int chunkX = 0; chunkX < 32; chunkX++) {
for (int chunkZ = 0; chunkZ < 32; chunkZ++) {
if (chunks[chunkX][chunkZ] == null) {
continue;
}
List<BlockPos> locs = chunks[chunkX][chunkZ].getAbsoluteBlocks(block);
if (locs == null) {
continue;
}
for (BlockPos pos : locs) {
res.add(pos);
}
}
}
return res;
}
final synchronized void updateCachedChunk(int chunkX, int chunkZ, CachedChunk chunk) {
this.chunks[chunkX][chunkZ] = chunk; this.chunks[chunkX][chunkZ] = chunk;
hasUnsavedChanges = true; hasUnsavedChanges = true;
} }
private CachedChunk getChunk(int chunkX, int chunkZ) {
return this.chunks[chunkX][chunkZ];
}
public void forEachChunk(Consumer<CachedChunk> consumer) { public synchronized final void save(String directory) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
CachedChunk chunk = getChunk(x, z);
if (chunk != null) {
consumer.accept(chunk);
}
}
}
}
public final void save(String directory) {
if (!hasUnsavedChanges) { if (!hasUnsavedChanges) {
return; return;
} }
@@ -139,7 +144,22 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
} }
out.writeInt(~CACHED_REGION_MAGIC); for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
if (chunks[x][z] != null) {
Map<String, List<BlockPos>> locs = chunks[x][z].getRelativeBlocks();
out.writeShort(locs.entrySet().size());
for (Map.Entry<String, List<BlockPos>> entry : locs.entrySet()) {
out.writeUTF(entry.getKey());
out.writeShort(entry.getValue().size());
for (BlockPos pos : entry.getValue()) {
out.writeByte((byte) (pos.getZ() << 4 | pos.getX()));
out.writeByte((byte) (pos.getY()));
}
}
}
}
}
} }
hasUnsavedChanges = false; hasUnsavedChanges = false;
System.out.println("Saved region successfully"); System.out.println("Saved region successfully");
@@ -148,7 +168,7 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
public void load(String directory) { public synchronized void load(String directory) {
try { try {
Path path = Paths.get(directory); Path path = Paths.get(directory);
if (!Files.exists(path)) if (!Files.exists(path))
@@ -174,6 +194,7 @@ public final class CachedRegion implements IBlockTypeAccess {
throw new IOException("Bad magic value " + magic); throw new IOException("Bad magic value " + magic);
} }
CachedChunk[][] tmpCached = new CachedChunk[32][32]; CachedChunk[][] tmpCached = new CachedChunk[32][32];
Map<String, List<BlockPos>>[][] location = new Map[32][32];
for (int z = 0; z < 32; z++) { for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) { for (int x = 0; x < 32; x++) {
int isChunkPresent = in.read(); int isChunkPresent = in.read();
@@ -181,7 +202,12 @@ public final class CachedRegion implements IBlockTypeAccess {
case CHUNK_PRESENT: case CHUNK_PRESENT:
byte[] bytes = new byte[CachedChunk.SIZE_IN_BYTES]; byte[] bytes = new byte[CachedChunk.SIZE_IN_BYTES];
in.readFully(bytes); in.readFully(bytes);
tmpCached[x][z] = new CachedChunk(x, z, BitSet.valueOf(bytes), new String[256]); location[x][z] = new HashMap<>();
int regionX = this.x;
int regionZ = this.z;
int chunkX = x + 32 * regionX;
int chunkZ = z + 32 * regionZ;
tmpCached[x][z] = new CachedChunk(chunkX, chunkZ, BitSet.valueOf(bytes), new String[256], location[x][z]);
break; break;
case CHUNK_NOT_PRESENT: case CHUNK_NOT_PRESENT:
tmpCached[x][z] = null; tmpCached[x][z] = null;
@@ -200,9 +226,33 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
} }
int fileEndMagic = in.readInt(); for (int z = 0; z < 32; z++) {
if (fileEndMagic != ~magic) { for (int x = 0; x < 32; x++) {
throw new IOException("Bad end of file magic"); if (tmpCached[x][z] != null) {
// 16 * 16 * 256 = 65536 so a short is enough
// ^ haha jokes on leijurv, java doesn't have unsigned types so that isn't correct
// also why would you have more than 32767 special blocks in a chunk
// haha double jokes on you now it works for 65535 not just 32767
int numSpecialBlockTypes = in.readShort() & 0xffff;
for (int i = 0; i < numSpecialBlockTypes; i++) {
String blockName = in.readUTF();
List<BlockPos> locs = new ArrayList<>();
location[x][z].put(blockName, locs);
int numLocations = in.readShort() & 0xffff;
if (numLocations == 0) {
// an entire chunk full of air can happen in the end
numLocations = 65536;
}
for (int j = 0; j < numLocations; j++) {
byte xz = in.readByte();
int X = xz & 0x0f;
int Z = (xz >>> 4) & 0x0f;
int Y = in.readByte() & 0xff;
locs.add(new BlockPos(X, Y, Z));
}
}
}
}
} }
// only if the entire file was uncorrupted do we actually set the chunks // only if the entire file was uncorrupted do we actually set the chunks
for (int x = 0; x < 32; x++) { for (int x = 0; x < 32; x++) {
@@ -219,15 +269,6 @@ public final class CachedRegion implements IBlockTypeAccess {
} }
} }
private static boolean isAllZeros(final byte[] array) {
for (byte b : array) {
if (b != 0) {
return false;
}
}
return true;
}
/** /**
* @return The region x coordinate * @return The region x coordinate
*/ */
+63 -5
View File
@@ -17,16 +17,18 @@
package baritone.chunk; package baritone.chunk;
import baritone.Baritone;
import baritone.utils.pathing.IBlockTypeAccess; import baritone.utils.pathing.IBlockTypeAccess;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.BitSet; import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer; import java.util.function.Consumer;
@@ -64,6 +66,21 @@ public final class CachedWorld implements IBlockTypeAccess {
// Insert an invalid region element // Insert an invalid region element
cachedRegions.put(0, null); cachedRegions.put(0, null);
new PackerThread().start(); new PackerThread().start();
new Thread() {
public void run() {
try {
while (true) {
// since a region only saves if it's been modified since its last save
// saving every 10 minutes means that once it's time to exit
// we'll only have a couple regions to save
save();
Thread.sleep(600000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}.start();
} }
public final void queueForPacking(Chunk chunk) { public final void queueForPacking(Chunk chunk) {
@@ -84,12 +101,45 @@ public final class CachedWorld implements IBlockTypeAccess {
return region.getBlock(x & 511, y, z & 511); return region.getBlock(x & 511, y, z & 511);
} }
public final LinkedList<BlockPos> getLocationsOf(String block, int minimum, int maxRegionDistanceSq) {
LinkedList<BlockPos> res = new LinkedList<>();
int playerRegionX = playerFeet().getX() >> 9;
int playerRegionZ = playerFeet().getZ() >> 9;
int searchRadius = 0;
while (searchRadius <= maxRegionDistanceSq) {
for (int xoff = -searchRadius; xoff <= searchRadius; xoff++) {
for (int zoff = -searchRadius; zoff <= searchRadius; zoff++) {
int distance = xoff * xoff + zoff * zoff;
if (distance != searchRadius) {
continue;
}
int regionX = xoff + playerRegionX;
int regionZ = zoff + playerRegionZ;
CachedRegion region = getOrCreateRegion(regionX, regionZ);
if (region != null)
for (BlockPos pos : region.getLocationsOf(block))
res.add(pos);
}
}
if (res.size() >= minimum) {
return res;
}
searchRadius++;
}
return res;
}
private void updateCachedChunk(CachedChunk chunk) { private void updateCachedChunk(CachedChunk chunk) {
CachedRegion region = getOrCreateRegion(chunk.x >> 5, chunk.z >> 5); CachedRegion region = getOrCreateRegion(chunk.x >> 5, chunk.z >> 5);
region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk); region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk);
} }
public final void save() { public final void save() {
if (!Baritone.settings().chunkCaching.get()) {
System.out.println("Not saving to disk; chunk caching is disabled.");
return;
}
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
this.cachedRegions.values().forEach(region -> { this.cachedRegions.values().forEach(region -> {
if (region != null) if (region != null)
@@ -99,6 +149,16 @@ public final class CachedWorld implements IBlockTypeAccess {
System.out.println("World save took " + (now - start) + "ms"); System.out.println("World save took " + (now - start) + "ms");
} }
public final void reloadAllFromDisk() {
long start = System.currentTimeMillis();
this.cachedRegions.values().forEach(region -> {
if (region != null)
region.load(this.directory);
});
long now = System.currentTimeMillis();
System.out.println("World load took " + (now - start) + "ms");
}
/** /**
* Returns the region at the specified region coordinates * Returns the region at the specified region coordinates
* *
@@ -118,7 +178,7 @@ public final class CachedWorld implements IBlockTypeAccess {
* @param regionZ The region Z coordinate * @param regionZ The region Z coordinate
* @return The region located at the specified coordinates * @return The region located at the specified coordinates
*/ */
private CachedRegion getOrCreateRegion(int regionX, int regionZ) { private synchronized CachedRegion getOrCreateRegion(int regionX, int regionZ) {
return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> { return cachedRegions.computeIfAbsent(getRegionID(regionX, regionZ), id -> {
CachedRegion newRegion = new CachedRegion(regionX, regionZ); CachedRegion newRegion = new CachedRegion(regionX, regionZ);
newRegion.load(this.directory); newRegion.load(this.directory);
@@ -168,9 +228,7 @@ public final class CachedWorld implements IBlockTypeAccess {
} }
try { try {
Chunk chunk = queue.take(); Chunk chunk = queue.take();
BitSet packedChunk = ChunkPacker.createPackedChunk(chunk); CachedChunk cached = ChunkPacker.pack(chunk);
String[] packedOverview = ChunkPacker.createPackedOverview(chunk);
CachedChunk cached = new CachedChunk(chunk.x, chunk.z, packedChunk, packedOverview);
CachedWorld.this.updateCachedChunk(cached); CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z); //System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
} catch (InterruptedException e) { } catch (InterruptedException e) {
+44 -18
View File
@@ -28,9 +28,10 @@ import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import java.util.BitSet; import java.util.*;
/** /**
* @author Brady * @author Brady
@@ -40,30 +41,33 @@ public final class ChunkPacker implements Helper {
private ChunkPacker() {} private ChunkPacker() {}
public static BitSet createPackedChunk(Chunk chunk) { public static CachedChunk pack(Chunk chunk) {
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Map<String, List<BlockPos>> specialBlocks = new HashMap<>();
BitSet bitSet = new BitSet(CachedChunk.SIZE); BitSet bitSet = new BitSet(CachedChunk.SIZE);
try { try {
for (int y = 0; y < 256; y++) { for (int y = 0; y < 256; y++) {
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
int index = CachedChunk.getPositionIndex(x, y, z); int index = CachedChunk.getPositionIndex(x, y, z);
boolean[] bits = getPathingBlockType(chunk.getBlockState(x, y, z).getBlock()).getBits(); Block block = chunk.getBlockState(x, y, z).getBlock();
boolean[] bits = getPathingBlockType(block).getBits();
bitSet.set(index, bits[0]); bitSet.set(index, bits[0]);
bitSet.set(index + 1, bits[1]); bitSet.set(index + 1, bits[1]);
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(block)) {
String name = blockToString(block);
specialBlocks.computeIfAbsent(name, b -> new ArrayList<>()).add(new BlockPos(x, y, z));
}
} }
} }
} }
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
} }
//System.out.println("Packed special blocks: " + specialBlocks);
long end = System.currentTimeMillis(); long end = System.currentTimeMillis();
//System.out.println("Chunk packing took " + (end - start) + "ms for " + chunk.x + "," + chunk.z); //System.out.println("Chunk packing took " + (end - start) + "ms for " + chunk.x + "," + chunk.z);
return bitSet;
}
public static String[] createPackedOverview(Chunk chunk) {
long start = System.currentTimeMillis();
String[] blockNames = new String[256]; String[] blockNames = new String[256];
for (int z = 0; z < 16; z++) { for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) { for (int x = 0; x < 16; x++) {
@@ -75,17 +79,29 @@ public final class ChunkPacker implements Helper {
break; break;
} }
} }
ResourceLocation loc = Block.REGISTRY.getNameForObject(blockState.getBlock()); String name = blockToString(blockState.getBlock());
String name = loc.getPath(); // normally, only write the part after the minecraft:
if (!loc.getNamespace().equals("minecraft")) {
// Baritone is running on top of forge with mods installed, perhaps?
name = loc.toString(); // include the namespace with the colon
}
blockNames[z << 4 | x] = name; blockNames[z << 4 | x] = name;
} }
} }
long end = System.currentTimeMillis(); CachedChunk cached = new CachedChunk(chunk.x, chunk.z, bitSet, blockNames, specialBlocks);
return blockNames; return cached;
}
public static String blockToString(Block block) {
ResourceLocation loc = Block.REGISTRY.getNameForObject(block);
String name = loc.getPath(); // normally, only write the part after the minecraft:
if (!loc.getNamespace().equals("minecraft")) {
// Baritone is running on top of forge with mods installed, perhaps?
name = loc.toString(); // include the namespace with the colon
}
return name;
}
public static Block stringToBlock(String name) {
if (!name.contains(":")) {
name = "minecraft:" + name;
}
return Block.getBlockFromName(name);
} }
private static PathingBlockType getPathingBlockType(Block block) { private static PathingBlockType getPathingBlockType(Block block) {
@@ -96,7 +112,6 @@ public final class ChunkPacker implements Helper {
if (MovementHelper.avoidWalkingInto(block)) { if (MovementHelper.avoidWalkingInto(block)) {
return PathingBlockType.AVOID; return PathingBlockType.AVOID;
} }
// We used to do an AABB check here // We used to do an AABB check here
// however, this failed in the nether when you were near a nether fortress // however, this failed in the nether when you were near a nether fortress
// because fences check their adjacent blocks in the world for their fence connection status to determine AABB shape // because fences check their adjacent blocks in the world for their fence connection status to determine AABB shape
@@ -118,7 +133,18 @@ public final class ChunkPacker implements Helper {
case AVOID: case AVOID:
return Blocks.LAVA.getDefaultState(); return Blocks.LAVA.getDefaultState();
case SOLID: case SOLID:
return Blocks.OBSIDIAN.getDefaultState(); // Dimension solid types
switch (mc.player.dimension) {
case -1:
return Blocks.NETHERRACK.getDefaultState();
case 0:
return Blocks.STONE.getDefaultState();
case 1:
return Blocks.END_STONE.getDefaultState();
}
// The fallback solid type
return Blocks.STONE.getDefaultState();
} }
} }
return null; return null;
@@ -0,0 +1,90 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.chunk;
import net.minecraft.util.math.BlockPos;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
/**
* A single waypoint
*
* @author leijurv
*/
public class Waypoint {
public final String name;
public final Tag tag;
private final long creationTimestamp;
public final BlockPos location;
public Waypoint(String name, Tag tag, BlockPos location) {
this(name, tag, location, System.currentTimeMillis());
}
Waypoint(String name, Tag tag, BlockPos location, long creationTimestamp) { // read from disk
this.name = name;
this.tag = tag;
this.location = location;
this.creationTimestamp = creationTimestamp;
}
@Override
public boolean equals(Object o) {
if (o == null) {
return false;
}
if (!(o instanceof Waypoint)) {
return false;
}
Waypoint w = (Waypoint) o;
return name.equals(w.name) && tag == w.tag && location.equals(w.location);
}
@Override
public int hashCode() {
return name.hashCode() + tag.hashCode() + location.hashCode(); //lol
}
public long creationTimestamp() {
return creationTimestamp;
}
public String toString() {
return name + " " + location.toString() + " " + new Date(creationTimestamp).toString();
}
public enum Tag {
HOME, DEATH, BED, USER;
}
public static final Map<String, Tag> TAG_MAP;
static {
HashMap<String, Tag> map = new HashMap<>();
map.put("home", Tag.HOME);
map.put("base", Tag.HOME);
map.put("bed", Tag.BED);
map.put("spawn", Tag.BED);
map.put("death", Tag.DEATH);
TAG_MAP = Collections.unmodifiableMap(map);
}
}
+89 -1
View File
@@ -17,12 +17,27 @@
package baritone.chunk; package baritone.chunk;
import java.io.IOException; import net.minecraft.util.math.BlockPos;
import java.io.*;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*;
/**
* Waypoints for a world
*
* @author leijurv
*/
public class Waypoints { public class Waypoints {
/**
* Magic value to detect invalid waypoint files
*/
private static final long WAYPOINT_MAGIC_VALUE = 121977993584L; // good value
private final Path directory; private final Path directory;
private final Map<Waypoint.Tag, Set<Waypoint>> waypoints;
Waypoints(Path directory) { Waypoints(Path directory) {
this.directory = directory; this.directory = directory;
@@ -32,5 +47,78 @@ public class Waypoints {
} catch (IOException ignored) {} } catch (IOException ignored) {}
} }
System.out.println("Would save waypoints to " + directory); System.out.println("Would save waypoints to " + directory);
this.waypoints = new HashMap<>();
load();
}
private void load() {
for (Waypoint.Tag tag : Waypoint.Tag.values()) {
load(tag);
}
}
private synchronized void load(Waypoint.Tag tag) {
waypoints.put(tag, new HashSet<>());
Path fileName = directory.resolve(tag.name().toLowerCase() + ".mp4");
if (!Files.exists(fileName))
return;
try (
FileInputStream fileIn = new FileInputStream(fileName.toFile());
BufferedInputStream bufIn = new BufferedInputStream(fileIn);
DataInputStream in = new DataInputStream(bufIn)
) {
long magic = in.readLong();
if (magic != WAYPOINT_MAGIC_VALUE) {
throw new IOException("Bad magic value " + magic);
}
long length = in.readLong(); // Yes I want 9,223,372,036,854,775,807 waypoints, do you not?
while (length-- > 0) {
String name = in.readUTF();
long creationTimestamp = in.readLong();
int x = in.readInt();
int y = in.readInt();
int z = in.readInt();
waypoints.get(tag).add(new Waypoint(name, tag, new BlockPos(x, y, z), creationTimestamp));
}
} catch (IOException ignored) {}
}
private synchronized void save(Waypoint.Tag tag) {
Path fileName = directory.resolve(tag.name().toLowerCase() + ".mp4");
try (
FileOutputStream fileOut = new FileOutputStream(fileName.toFile());
BufferedOutputStream bufOut = new BufferedOutputStream(fileOut);
DataOutputStream out = new DataOutputStream(bufOut)
) {
out.writeLong(WAYPOINT_MAGIC_VALUE);
out.writeLong(waypoints.get(tag).size());
for (Waypoint waypoint : waypoints.get(tag)) {
out.writeUTF(waypoint.name);
out.writeLong(waypoint.creationTimestamp());
out.writeInt(waypoint.location.getX());
out.writeInt(waypoint.location.getY());
out.writeInt(waypoint.location.getZ());
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
public Set<Waypoint> getByTag(Waypoint.Tag tag) {
return Collections.unmodifiableSet(waypoints.get(tag));
}
public Waypoint getMostRecentByTag(Waypoint.Tag tag) {
// Find a waypoint of the given tag which has the greatest timestamp value, indicating the most recent
return this.waypoints.get(tag).stream().min(Comparator.comparingLong(w -> -w.creationTimestamp())).orElse(null);
}
public void addWaypoint(Waypoint waypoint) {
// no need to check for duplicate, because it's a Set not a List
waypoints.get(waypoint.tag).add(waypoint);
save(waypoint.tag);
} }
} }
@@ -19,6 +19,11 @@ package baritone.chunk;
import java.nio.file.Path; import java.nio.file.Path;
/**
* Data about a world, from baritone's point of view. Includes cached chunks, waypoints, and map data.
*
* @author leijurv
*/
public class WorldData { public class WorldData {
public final CachedWorld cache; public final CachedWorld cache;
public final Waypoints waypoints; public final Waypoints waypoints;
@@ -26,6 +26,7 @@ import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.world.WorldServer; import net.minecraft.world.WorldServer;
import java.io.File; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@@ -52,6 +53,7 @@ public enum WorldProvider implements Helper {
public final void initWorld(WorldClient world) { public final void initWorld(WorldClient world) {
int dimensionID = world.provider.getDimensionType().getId(); int dimensionID = world.provider.getDimensionType().getId();
File directory; File directory;
File readme;
IntegratedServer integratedServer = mc.getIntegratedServer(); IntegratedServer integratedServer = mc.getIntegratedServer();
if (integratedServer != null) { if (integratedServer != null) {
WorldServer localServerWorld = integratedServer.getWorld(dimensionID); WorldServer localServerWorld = integratedServer.getWorld(dimensionID);
@@ -59,17 +61,26 @@ public enum WorldProvider implements Helper {
IAnvilChunkLoader loader = (IAnvilChunkLoader) provider.getChunkLoader(); IAnvilChunkLoader loader = (IAnvilChunkLoader) provider.getChunkLoader();
directory = loader.getChunkSaveLocation(); directory = loader.getChunkSaveLocation();
if (!directory.getParentFile().getName().equals("saves")) { // Gets the "depth" of this directory relative the the game's run directory, 2 is the location of the world
if (directory.toPath().relativize(mc.gameDir.toPath()).getNameCount() != 2) {
// subdirectory of the main save directory for this world // subdirectory of the main save directory for this world
directory = directory.getParentFile(); directory = directory.getParentFile();
} }
directory = new File(directory, "baritone"); directory = new File(directory, "baritone");
readme = directory;
} else { } else {
//remote //remote
directory = new File(Baritone.INSTANCE.getDir(), mc.getCurrentServerData().serverIP); directory = new File(Baritone.INSTANCE.getDir(), mc.getCurrentServerData().serverIP);
readme = Baritone.INSTANCE.getDir();
} }
// lol wtf is this baritone folder in my minecraft save?
try (FileOutputStream out = new FileOutputStream(new File(readme, "readme.txt"))) {
// good thing we have a readme
out.write("https://github.com/cabaletta/baritone\n".getBytes());
} catch (IOException ignored) {}
directory = new File(directory, "DIM" + dimensionID); directory = new File(directory, "DIM" + dimensionID);
Path dir = directory.toPath(); Path dir = directory.toPath();
if (!Files.exists(dir)) { if (!Files.exists(dir)) {
@@ -42,10 +42,6 @@ import baritone.event.listener.IGameEventListener;
import baritone.utils.Helper; import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.interfaces.Toggleable; import baritone.utils.interfaces.Toggleable;
import net.minecraft.client.renderer.BufferBuilder;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.client.settings.KeyBinding; import net.minecraft.client.settings.KeyBinding;
import net.minecraft.world.chunk.Chunk; import net.minecraft.world.chunk.Chunk;
import org.lwjgl.input.Keyboard; import org.lwjgl.input.Keyboard;
@@ -111,15 +107,14 @@ public final class GameEventHandler implements IGameEventListener, Helper {
&& type == ChunkEvent.Type.UNLOAD && type == ChunkEvent.Type.UNLOAD
&& mc.world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ()); && mc.world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ());
if (Baritone.settings().chunkCaching.get()) { if (isPostPopulate || isPreUnload) {
if (isPostPopulate || isPreUnload) { WorldProvider.INSTANCE.ifWorldLoaded(world -> {
WorldProvider.INSTANCE.ifWorldLoaded(world -> { Chunk chunk = mc.world.getChunk(event.getX(), event.getZ());
Chunk chunk = mc.world.getChunk(event.getX(), event.getZ()); world.cache.queueForPacking(chunk);
world.cache.queueForPacking(chunk); });
});
}
} }
dispatch(listener -> listener.onChunkEvent(event)); dispatch(listener -> listener.onChunkEvent(event));
} }
@@ -136,19 +131,17 @@ public final class GameEventHandler implements IGameEventListener, Helper {
@Override @Override
public final void onWorldEvent(WorldEvent event) { public final void onWorldEvent(WorldEvent event) {
if (Baritone.settings().chunkCaching.get()) { WorldProvider cache = WorldProvider.INSTANCE;
WorldProvider cache = WorldProvider.INSTANCE;
switch (event.getState()) { switch (event.getState()) {
case PRE: case PRE:
cache.closeWorld(); cache.closeWorld();
break; break;
case POST: case POST:
cache.closeWorld(); cache.closeWorld();
if (event.getWorld() != null) if (event.getWorld() != null)
cache.initWorld(event.getWorld()); cache.initWorld(event.getWorld());
break; break;
}
} }
dispatch(listener -> listener.onWorldEvent(event)); dispatch(listener -> listener.onWorldEvent(event));
@@ -174,6 +167,21 @@ public final class GameEventHandler implements IGameEventListener, Helper {
dispatch(listener -> listener.onPlayerRelativeMove(event)); dispatch(listener -> listener.onPlayerRelativeMove(event));
} }
@Override
public void onBlockInteract(BlockInteractEvent event) {
dispatch(listener -> listener.onBlockInteract(event));
}
@Override
public void onPlayerDeath() {
dispatch(IGameEventListener::onPlayerDeath);
}
@Override
public void onPathEvent(PathEvent event) {
dispatch(listener -> listener.onPathEvent(event));
}
public final void registerEventListener(IGameEventListener listener) { public final void registerEventListener(IGameEventListener listener) {
this.listeners.add(listener); this.listeners.add(listener);
} }
@@ -185,27 +193,4 @@ public final class GameEventHandler implements IGameEventListener, Helper {
private boolean canDispatch(IGameEventListener listener) { private boolean canDispatch(IGameEventListener listener) {
return !(listener instanceof Toggleable) || ((Toggleable) listener).isEnabled(); return !(listener instanceof Toggleable) || ((Toggleable) listener).isEnabled();
} }
private void drawChunkLine(int posX, int posZ, float partialTicks) {
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(770, 771, 1, 0);
GlStateManager.color(1.0F, 1.0F, 0.0F, 0.4F);
GlStateManager.glLineWidth(2.0F);
GlStateManager.disableTexture2D();
Tessellator tessellator = Tessellator.getInstance();
BufferBuilder buffer = tessellator.getBuffer();
double d0 = mc.getRenderManager().viewerPosX;
double d1 = mc.getRenderManager().viewerPosY;
double d2 = mc.getRenderManager().viewerPosZ;
buffer.begin(3, DefaultVertexFormats.POSITION);
buffer.pos(posX - d0, 0 - d1, posZ - d2).endVertex();
buffer.pos(posX - d0, 256 - d1, posZ - d2).endVertex();
tessellator.draw();
GlStateManager.enableDepth();
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
} }
@@ -0,0 +1,69 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
import net.minecraft.util.math.BlockPos;
/**
* @author Brady
* @since 8/22/2018
*/
public final class BlockInteractEvent {
/**
* The position of the block interacted with
*/
private final BlockPos pos;
/**
* The type of interaction that occurred
*/
private final Type type;
public BlockInteractEvent(BlockPos pos, Type type) {
this.pos = pos;
this.type = type;
}
/**
* @return The position of the block interacted with
*/
public final BlockPos getPos() {
return this.pos;
}
/**
* @return The type of interaction with the target block
*/
public final Type getType() {
return this.type;
}
public enum Type {
/**
* We're breaking the target block.
*/
BREAK,
/**
* We're right clicking on the target block. Either placing or interacting with.
*/
USE
}
}
@@ -0,0 +1,32 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.event.events;
public enum PathEvent {
CALC_STARTED,
CALC_FINISHED_NOW_EXECUTING,
CALC_FAILED,
NEXT_SEGMENT_CALC_STARTED,
NEXT_SEGMENT_CALC_FINISHED,
CONTINUING_ONTO_PLANNED_NEXT,
SPLICING_ONTO_NEXT_EARLY,
AT_GOAL,
PATH_FINISHED_NEXT_STILL_CALCULATING,
NEXT_CALC_FAILED,
DISCARD_NEXT
}
@@ -41,9 +41,8 @@ import baritone.event.events.*;
* overridden with empty bodies, allowing inheritors of this class to choose * overridden with empty bodies, allowing inheritors of this class to choose
* which events they would like to listen in on. * which events they would like to listen in on.
* *
* @see IGameEventListener
*
* @author Brady * @author Brady
* @see IGameEventListener
* @since 8/1/2018 6:29 PM * @since 8/1/2018 6:29 PM
*/ */
public interface AbstractGameEventListener extends IGameEventListener { public interface AbstractGameEventListener extends IGameEventListener {
@@ -80,4 +79,13 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override @Override
default void onPlayerRelativeMove(RelativeMoveEvent event) {} default void onPlayerRelativeMove(RelativeMoveEvent event) {}
@Override
default void onBlockInteract(BlockInteractEvent event) {}
@Override
default void onPlayerDeath() {}
@Override
default void onPathEvent(PathEvent event) {}
} }
@@ -39,6 +39,7 @@ import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.EntityRenderer; import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.settings.GameSettings; import net.minecraft.client.settings.GameSettings;
@@ -46,6 +47,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.InventoryPlayer; import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.network.NetworkManager; import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet; import net.minecraft.network.Packet;
import net.minecraft.util.text.ITextComponent;
/** /**
* @author Brady * @author Brady
@@ -132,4 +134,26 @@ public interface IGameEventListener {
* @see Entity#moveRelative(float, float, float, float) * @see Entity#moveRelative(float, float, float, float)
*/ */
void onPlayerRelativeMove(RelativeMoveEvent event); void onPlayerRelativeMove(RelativeMoveEvent event);
/**
* Called when the local player interacts with a block, whether it is breaking or opening/placing.
*
* @see Minecraft#clickMouse()
* @see Minecraft#rightClickMouse()
*/
void onBlockInteract(BlockInteractEvent event);
/**
* Called when the local player dies, as indicated by the creation of the {@link GuiGameOver} screen.
*
* @see GuiGameOver(ITextComponent)
*/
void onPlayerDeath();
/**
* When the pathfinder's state changes
*
* @param event
*/
void onPathEvent(PathEvent event);
} }
@@ -1,40 +1,43 @@
/* /*
* This file is part of Baritone. * This file is part of Baritone.
* *
* Baritone is free software: you can redistribute it and/or modify * Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or * the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version. * (at your option) any later version.
* *
* Baritone is distributed in the hope that it will be useful, * Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>. * along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/ */
package baritone.launch.mixins; package baritone.launch.mixins;
import net.minecraft.client.main.Main; import com.google.common.base.MoreObjects;
import org.spongepowered.asm.mixin.Mixin; import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.mixin.injection.At; import net.minecraft.util.math.Vec3i;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import javax.annotation.Nonnull;
/**
* @author Brady /**
* @since 7/31/2018 10:18 PM * @author Brady
*/ * @since 8/25/2018
@Mixin(Main.class) */
public class MixinMain { @Mixin(BlockPos.class)
public abstract class MixinBlockPos extends Vec3i {
@Inject(
method = "main", public MixinBlockPos(int xIn, int yIn, int zIn) {
at = @At("HEAD") super(xIn, yIn, zIn);
) }
private static void main(String[] args, CallbackInfo ci) {
System.setProperty("java.net.preferIPv4Stack", "true"); @Override
} @Nonnull
} public String toString() {
return MoreObjects.toStringHelper("BlockPos").add("x", this.getX()).add("y", this.getY()).add("z", this.getZ()).toString();
}
}
@@ -34,7 +34,8 @@ public class MixinGameSettings {
method = "isKeyDown", method = "isKeyDown",
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z" target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
) )
) )
private static boolean isKeyDown(int keyCode) { private static boolean isKeyDown(int keyCode) {
@@ -37,7 +37,8 @@ public class MixinGuiContainer {
}, },
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z" target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
) )
) )
private boolean isKeyDown(int keyCode) { private boolean isKeyDown(int keyCode) {
@@ -38,7 +38,8 @@ public class MixinGuiScreen {
}, },
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z" target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
) )
) )
private static boolean isKeyDown(int keyCode) { private static boolean isKeyDown(int keyCode) {
@@ -19,13 +19,19 @@ package baritone.launch.mixins;
import baritone.Baritone; import baritone.Baritone;
import baritone.behavior.impl.PathingBehavior; import baritone.behavior.impl.PathingBehavior;
import baritone.event.events.BlockInteractEvent;
import baritone.event.events.TickEvent; import baritone.event.events.TickEvent;
import baritone.event.events.WorldEvent; import baritone.event.events.WorldEvent;
import baritone.event.events.type.EventState; import baritone.event.events.type.EventState;
import baritone.utils.ExampleBaritoneControl; import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.gui.GuiScreen;
import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumActionResult;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import org.spongepowered.asm.lib.Opcodes; import org.spongepowered.asm.lib.Opcodes;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Shadow;
@@ -33,6 +39,7 @@ import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect; import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/** /**
* @author Brady * @author Brady
@@ -42,6 +49,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMinecraft { public class MixinMinecraft {
@Shadow private int leftClickCounter; @Shadow private int leftClickCounter;
@Shadow public EntityPlayerSP player;
@Shadow public WorldClient world; @Shadow public WorldClient world;
@Inject( @Inject(
@@ -78,7 +86,8 @@ public class MixinMinecraft {
method = "runTickKeyboard", method = "runTickKeyboard",
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z" target = "org/lwjgl/input/Keyboard.isKeyDown(I)Z",
remap = false
) )
) )
private boolean Keyboard$isKeyDown(int keyCode) { private boolean Keyboard$isKeyDown(int keyCode) {
@@ -93,23 +102,6 @@ public class MixinMinecraft {
Baritone.INSTANCE.getGameEventHandler().onProcessKeyBinds(); Baritone.INSTANCE.getGameEventHandler().onProcessKeyBinds();
} }
@Redirect(
method = {
"setIngameFocus",
"runTick"
},
at = @At(
value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "net/minecraft/client/Minecraft.leftClickCounter:I",
ordinal = 0
)
)
private void setLeftClickCounter(Minecraft mc, int value) {
if (!Baritone.INSTANCE.isInitialized() || !Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindAttack))
this.leftClickCounter = value;
}
@Inject( @Inject(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V", method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("HEAD") at = @At("HEAD")
@@ -153,6 +145,30 @@ public class MixinMinecraft {
) )
) )
private boolean isAllowUserInput(GuiScreen screen) { private boolean isAllowUserInput(GuiScreen screen) {
return PathingBehavior.INSTANCE.getCurrent() != null || screen.allowUserInput; return (PathingBehavior.INSTANCE.getCurrent() != null && player != null) || screen.allowUserInput;
}
@Inject(
method = "clickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/multiplayer/PlayerControllerMP.clickBlock(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)Z"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockBreak(CallbackInfo ci, BlockPos pos) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.BREAK));
}
@Inject(
method = "rightClickMouse",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/entity/EntityPlayerSP.swingArm(Lnet/minecraft/util/EnumHand;)V"
),
locals = LocalCapture.CAPTURE_FAILHARD
)
private void onBlockUse(CallbackInfo ci, EnumHand var1[], int var2, int var3, EnumHand enumhand, ItemStack itemstack, BlockPos blockpos, int i, EnumActionResult enumactionresult) {
Baritone.INSTANCE.getGameEventHandler().onBlockInteract(new BlockInteractEvent(blockpos, BlockInteractEvent.Type.USE));
} }
} }
@@ -22,6 +22,7 @@ import baritone.event.events.ChunkEvent;
import baritone.event.events.type.EventState; import baritone.event.events.type.EventState;
import net.minecraft.client.network.NetHandlerPlayClient; import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.SPacketChunkData; import net.minecraft.network.play.server.SPacketChunkData;
import net.minecraft.network.play.server.SPacketCombatEvent;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.Inject;
@@ -66,4 +67,15 @@ public class MixinNetHandlerPlayClient {
) )
); );
} }
@Inject(
method = "handleCombatEvent",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/Minecraft.displayGuiScreen(Lnet/minecraft/client/gui/GuiScreen;)V"
)
)
private void onPlayerDeath(SPacketCombatEvent packetIn, CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onPlayerDeath();
}
} }
@@ -64,8 +64,7 @@ public abstract class MixinNetworkManager {
at = @At( at = @At(
value = "INVOKE", value = "INVOKE",
target = "net/minecraft/network/Packet.processPacket(Lnet/minecraft/network/INetHandler;)V" target = "net/minecraft/network/Packet.processPacket(Lnet/minecraft/network/INetHandler;)V"
), )
remap = false
) )
private void preProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) { private void preProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent(EventState.PRE, packet)); Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent(EventState.PRE, packet));
@@ -73,8 +72,7 @@ public abstract class MixinNetworkManager {
@Inject( @Inject(
method = "channelRead0", method = "channelRead0",
at = @At("RETURN"), at = @At("RETURN")
remap = false
) )
private void postProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) { private void postProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
if (this.channel.isOpen()) if (this.channel.isOpen())
@@ -77,8 +77,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
int numNodes = 0; int numNodes = 0;
int numEmptyChunk = 0; int numEmptyChunk = 0;
boolean favoring = favoredPositions.isPresent(); boolean favoring = favoredPositions.isPresent();
boolean cache = Baritone.settings().chunkCaching.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior
int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get();
double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get(); double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get(); boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get();
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.currentTimeMillis() < timeoutTime) { while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.currentTimeMillis() < timeoutTime) {
@@ -112,11 +111,9 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
} }
BetterBlockPos dest = (BetterBlockPos) movementToGetToNeighbor.getDest(); BetterBlockPos dest = (BetterBlockPos) movementToGetToNeighbor.getDest();
boolean isPositionCached = false; boolean isPositionCached = false;
if (cache) { if (WorldProvider.INSTANCE.getCurrentWorld() != null) {
if (WorldProvider.INSTANCE.getCurrentWorld() != null) { if (WorldProvider.INSTANCE.getCurrentWorld().cache.getBlock(dest) != null) {
if (WorldProvider.INSTANCE.getCurrentWorld().cache.getBlock(dest) != null) { isPositionCached = true;
isPositionCached = true;
}
} }
} }
if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(dest) instanceof EmptyChunk) { if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(dest) instanceof EmptyChunk) {
@@ -64,6 +64,9 @@ public class GoalXZ implements Goal {
} }
public static double calculate(double xDiff, double zDiff) { public static double calculate(double xDiff, double zDiff) {
if (Baritone.settings().pythagoreanMetric.get()) {
return Math.sqrt(xDiff * xDiff + zDiff * zDiff) * Baritone.settings().costHeuristic.get();
}
//This is a combination of pythagorean and manhattan distance //This is a combination of pythagorean and manhattan distance
//It takes into account the fact that pathing can either walk diagonally or forwards //It takes into account the fact that pathing can either walk diagonally or forwards
@@ -48,7 +48,7 @@ public class GoalYLevel implements Goal {
} }
if (pos.getY() < level) { if (pos.getY() < level) {
// need to ascend // need to ascend
return (level - pos.getY()) * JUMP_ONE_BLOCK_COST * 0.9; return (level - pos.getY()) * JUMP_ONE_BLOCK_COST;
} }
return 0; return 0;
} }
@@ -29,9 +29,12 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder; import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine; import net.minecraft.block.BlockVine;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional; import java.util.Optional;
import static baritone.utils.InputOverrideHandler.Input; import static baritone.utils.InputOverrideHandler.Input;
@@ -54,6 +57,8 @@ public abstract class Movement implements Helper, MovementHelper {
*/ */
protected final BlockPos[] positionsToPlace; protected final BlockPos[] positionsToPlace;
private boolean didBreakLastTick;
private Double cost; private Double cost;
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos[] toPlace) { protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos[] toPlace) {
@@ -100,7 +105,6 @@ public abstract class Movement implements Helper, MovementHelper {
* @return Status * @return Status
*/ */
public MovementStatus update() { public MovementStatus update() {
player().setSprinting(false);
MovementState latestState = updateState(currentState); MovementState latestState = updateState(currentState);
if (BlockStateInterface.isLiquid(playerFeet())) { if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true); latestState.setInput(Input.JUMP, true);
@@ -114,10 +118,29 @@ public abstract class Movement implements Helper, MovementHelper {
// TODO: calculate movement inputs from latestState.getGoal().position // TODO: calculate movement inputs from latestState.getGoal().position
// latestState.getTarget().position.ifPresent(null); NULL CONSUMER REALLY SHOULDN'T BE THE FINAL THING YOU SHOULD REALLY REPLACE THIS WITH ALMOST ACTUALLY ANYTHING ELSE JUST PLEASE DON'T LEAVE IT AS IT IS THANK YOU KANYE // latestState.getTarget().position.ifPresent(null); NULL CONSUMER REALLY SHOULDN'T BE THE FINAL THING YOU SHOULD REALLY REPLACE THIS WITH ALMOST ACTUALLY ANYTHING ELSE JUST PLEASE DON'T LEAVE IT AS IT IS THANK YOU KANYE
this.didBreakLastTick = false;
latestState.getInputStates().forEach((input, forced) -> { latestState.getInputStates().forEach((input, forced) -> {
RayTraceResult trace = mc.objectMouseOver;
boolean isBlockTrace = trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK;
boolean isLeftClick = forced && input == Input.CLICK_LEFT;
// If we're forcing left click, we're in a gui screen, and we're looking
// at a block, break the block without a direct game input manipulation.
if (mc.currentScreen != null && isLeftClick && isBlockTrace) {
BlockBreakHelper.tryBreakBlock(trace.getBlockPos(), trace.sideHit);
this.didBreakLastTick = true;
return;
}
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced); Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(input, forced);
}); });
latestState.getInputStates().replaceAll((input, forced) -> false); latestState.getInputStates().replaceAll((input, forced) -> false);
if (!this.didBreakLastTick)
BlockBreakHelper.stopBreakingBlock();
currentState = latestState; currentState = latestState;
if (isFinished()) if (isFinished())
@@ -187,41 +210,58 @@ public abstract class Movement implements Helper, MovementHelper {
currentState.setStatus(MovementStatus.CANCELED); currentState.setStatus(MovementStatus.CANCELED);
} }
public void reset() {
currentState = new MovementState().setStatus(MovementStatus.PREPPING);
}
public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) { public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) {
/* if (positionsToBreak.length == 0) {
double sum = 0; return 0;
HashSet<BlockPos> toBreak = new HashSet();
for (BlockPos positionsToBreak1 : positionsToBreak) {
toBreak.add(positionsToBreak1);
if (this instanceof ActionFall) {//if we are digging straight down, assume we have already broken the sand above us
continue;
}
BlockPos tmp = positionsToBreak1.up();
while (canFall(tmp)) {
toBreak.add(tmp);
tmp = tmp.up();
}
} }
for (BlockPos pos : toBreak) { if (positionsToBreak.length == 1) {
sum += getHardness(ts, Baritone.get(pos), pos); return MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[0], true);
if (sum >= COST_INF) {
return COST_INF;
}
} }
if (!Baritone.allowBreakOrPlace || !Baritone.hasThrowaway) { int firstColumnX = positionsToBreak[0].getX();
for (int i = 0; i < blocksToPlace.length; i++) { int firstColumnZ = positionsToBreak[0].getZ();
if (!canWalkOn(positionsToPlace[i])) { int firstColumnMaxY = positionsToBreak[0].getY();
return COST_INF; int firstColumnMaximalIndex = 0;
boolean hasSecondColumn = false;
int secondColumnX = -1;
int secondColumnZ = -1;
int secondColumnMaxY = -1;
int secondColumnMaximalIndex = -1;
for (int i = 0; i < positionsToBreak.length; i++) {
BlockPos pos = positionsToBreak[i];
if (pos.getX() == firstColumnX && pos.getZ() == firstColumnZ) {
if (pos.getY() > firstColumnMaxY) {
firstColumnMaxY = pos.getY();
firstColumnMaximalIndex = i;
}
} else {
if (!hasSecondColumn || (pos.getX() == secondColumnX && pos.getZ() == secondColumnZ)) {
if (hasSecondColumn) {
if (pos.getY() > secondColumnMaxY) {
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
hasSecondColumn = true;
secondColumnX = pos.getX();
secondColumnZ = pos.getZ();
secondColumnMaxY = pos.getY();
secondColumnMaximalIndex = i;
}
} else {
throw new IllegalStateException("I literally have no idea " + Arrays.asList(positionsToBreak));
} }
} }
}*/ }
//^ the above implementation properly deals with falling blocks, TODO integrate
double sum = 0; double sum = 0;
for (BlockPos pos : positionsToBreak) { for (int i = 0; i < positionsToBreak.length; i++) {
sum += MovementHelper.getMiningDurationTicks(ctx, pos); sum += MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[i], firstColumnMaximalIndex == i || secondColumnMaximalIndex == i);
if (sum >= COST_INF) { if (sum >= COST_INF) {
return COST_INF; break;
} }
} }
return sum; return sum;
@@ -243,15 +283,19 @@ public abstract class Movement implements Helper, MovementHelper {
return state; return state;
} }
public ArrayList<BlockPos> toBreakCached = null; public BlockPos getDirection() {
public ArrayList<BlockPos> toPlaceCached = null; return getDest().subtract(getSrc());
public ArrayList<BlockPos> toWalkIntoCached = null; }
public ArrayList<BlockPos> toBreak() { public List<BlockPos> toBreakCached = null;
public List<BlockPos> toPlaceCached = null;
public List<BlockPos> toWalkIntoCached = null;
public List<BlockPos> toBreak() {
if (toBreakCached != null) { if (toBreakCached != null) {
return toBreakCached; return toBreakCached;
} }
ArrayList<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToBreak) { for (BlockPos positionToBreak : positionsToBreak) {
if (!MovementHelper.canWalkThrough(positionToBreak)) { if (!MovementHelper.canWalkThrough(positionToBreak)) {
result.add(positionToBreak); result.add(positionToBreak);
@@ -261,11 +305,11 @@ public abstract class Movement implements Helper, MovementHelper {
return result; return result;
} }
public ArrayList<BlockPos> toPlace() { public List<BlockPos> toPlace() {
if (toPlaceCached != null) { if (toPlaceCached != null) {
return toPlaceCached; return toPlaceCached;
} }
ArrayList<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToPlace) { for (BlockPos positionToBreak : positionsToPlace) {
if (!MovementHelper.canWalkOn(positionToBreak)) { if (!MovementHelper.canWalkOn(positionToBreak)) {
result.add(positionToBreak); result.add(positionToBreak);
@@ -275,7 +319,7 @@ public abstract class Movement implements Helper, MovementHelper {
return result; return result;
} }
public ArrayList<BlockPos> toWalkInto() { // overridden by movementdiagonal public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
if (toWalkIntoCached == null) { if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>(); toWalkIntoCached = new ArrayList<>();
} }
@@ -24,15 +24,18 @@ import baritone.pathing.movement.movements.MovementDescend;
import baritone.pathing.movement.movements.MovementFall; import baritone.pathing.movement.movements.MovementFall;
import baritone.utils.*; import baritone.utils.*;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity; import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList; import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.Optional; import java.util.Optional;
@@ -75,52 +78,87 @@ public interface MovementHelper extends ActionCosts, Helper {
|| block instanceof BlockEndPortal) {//you can't actually walk through a lilypad from the side, and you shouldn't walk through fire || block instanceof BlockEndPortal) {//you can't actually walk through a lilypad from the side, and you shouldn't walk through fire
return false; return false;
} }
if (block instanceof BlockDoor || block instanceof BlockFenceGate) {
if (block == Blocks.IRON_DOOR) {
return false;
}
return true; // we can just open the door
}
if (block instanceof BlockSnow || block instanceof BlockTrapDoor) {
// we've already checked doors
// so the only remaining dynamic isPassables are snow, fence gate, and trapdoor
// 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)
if (mc.world.getChunk(pos) instanceof EmptyChunk) {
return true;
}
}
IBlockState up = BlockStateInterface.get(pos.up()); IBlockState up = BlockStateInterface.get(pos.up());
if (BlockStateInterface.isFlowing(state) || up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) { if (BlockStateInterface.isFlowing(state) || up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
return false; // Don't walk through flowing liquids return false; // Don't walk through flowing liquids
} }
if (block instanceof BlockDoor && !Blocks.IRON_DOOR.equals(block)) {
return true; // we can just open the door
}
return block.isPassable(mc.world, pos); return block.isPassable(mc.world, pos);
} }
static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) { static boolean isReplacable(BlockPos pos, IBlockState state) {
IBlockState door = BlockStateInterface.get(doorPos); // for MovementTraverse and MovementAscend
if (!(door.getBlock() instanceof BlockDoor)) { // block double plant defaults to true when the block doesn't match, so don't need to check that case
return true; // all other overrides just return true or false
} // the only case to deal with is snow
String facing = door.getValue(BlockDoor.FACING).getName(); /*
boolean open = door.getValue(BlockDoor.OPEN).booleanValue(); * public boolean isReplaceable(IBlockAccess worldIn, BlockPos pos)
/** * {
* yes this is dumb * return ((Integer)worldIn.getBlockState(pos).getValue(LAYERS)).intValue() == 1;
* change it if you want * }
*/ */
String playerFacing = ""; if (state.getBlock() instanceof BlockSnow) {
if (playerPos.equals(doorPos)) { // as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
return false; if (mc.world.getChunk(pos) instanceof EmptyChunk) {
return true;
}
} }
if (playerPos.north().equals(doorPos) || playerPos.south().equals(doorPos)) { return state.getBlock().isReplaceable(mc.world, pos);
playerFacing = "northsouth"; }
} else if (playerPos.east().equals(doorPos) || playerPos.west().equals(doorPos)) {
playerFacing = "eastwest"; static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
if (playerPos.equals(doorPos))
return false;
IBlockState state = BlockStateInterface.get(doorPos);
if (!(state.getBlock() instanceof BlockDoor))
return true;
return isHorizontalBlockPassable(doorPos, state, playerPos, BlockDoor.OPEN);
}
static boolean isGatePassable(BlockPos gatePos, BlockPos playerPos) {
if (playerPos.equals(gatePos))
return false;
IBlockState state = BlockStateInterface.get(gatePos);
if (!(state.getBlock() instanceof BlockFenceGate))
return true;
return isHorizontalBlockPassable(gatePos, state, playerPos, BlockFenceGate.OPEN);
}
static boolean isHorizontalBlockPassable(BlockPos blockPos, IBlockState blockState, BlockPos playerPos, PropertyBool propertyOpen) {
if (playerPos.equals(blockPos))
return false;
EnumFacing.Axis facing = blockState.getValue(BlockHorizontal.FACING).getAxis();
boolean open = blockState.getValue(propertyOpen);
EnumFacing.Axis playerFacing;
if (playerPos.north().equals(blockPos) || playerPos.south().equals(blockPos)) {
playerFacing = EnumFacing.Axis.Z;
} else if (playerPos.east().equals(blockPos) || playerPos.west().equals(blockPos)) {
playerFacing = EnumFacing.Axis.X;
} else { } else {
return true; return true;
} }
if (facing == "north" || facing == "south") { return facing == playerFacing == open;
if (open) {
return playerFacing == "northsouth";
} else {
return playerFacing == "eastwest";
}
} else {
if (open) {
return playerFacing == "eastwest";
} else {
return playerFacing == "northsouth";
}
}
} }
static boolean avoidWalkingInto(Block block) { static boolean avoidWalkingInto(Block block) {
@@ -170,12 +208,12 @@ public interface MovementHelper extends ActionCosts, Helper {
return BlockStateInterface.get(pos).getBlock() instanceof BlockFalling; return BlockStateInterface.get(pos).getBlock() instanceof BlockFalling;
} }
static double getMiningDurationTicks(CalculationContext context, BlockPos position) { static double getMiningDurationTicks(CalculationContext context, BlockPos position, boolean includeFalling) {
IBlockState state = BlockStateInterface.get(position); IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(context, position, state); return getMiningDurationTicks(context, position, state, includeFalling);
} }
static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state) { static double getMiningDurationTicks(CalculationContext context, BlockPos position, IBlockState state, boolean includeFalling) {
Block block = state.getBlock(); Block block = state.getBlock();
if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) { // TODO is the air check really necessary? Isn't air canWalkThrough? if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) { // TODO is the air check really necessary? Isn't air canWalkThrough?
if (!context.allowBreak()) { if (!context.allowBreak()) {
@@ -185,9 +223,17 @@ public interface MovementHelper extends ActionCosts, Helper {
return COST_INF; return COST_INF;
} }
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
return m / context.getToolSet().getStrVsBlock(state, position); double result = m / context.getToolSet().getStrVsBlock(state, position);
if (includeFalling) {
BlockPos up = position.up();
IBlockState above = BlockStateInterface.get(up);
if (above.getBlock() instanceof BlockFalling) {
result += getMiningDurationTicks(context, up, above, true);
}
}
return result;
} }
return 0; return 0; // we won't actually mine it, so don't check fallings above
} }
/** /**
@@ -266,22 +312,22 @@ public interface MovementHelper extends ActionCosts, Helper {
static Movement generateMovementFallOrDescend(BlockPos pos, BlockPos dest, CalculationContext calcContext) { static Movement generateMovementFallOrDescend(BlockPos pos, BlockPos dest, CalculationContext calcContext) {
// A // A
//SA //SA
// B // A
// B // B
// C // C
// D // D
//if S is where you start, both of B need to be air for a movementfall //if S is where you start, B needs to be air for a movementfall
//A is plausibly breakable by either descend or fall //A is plausibly breakable by either descend or fall
//C, D, etc determine the length of the fall //C, D, etc determine the length of the fall
for (int i = 1; i < 3; i++) {
if (!canWalkThrough(dest.down(i))) {
//if any of these two (B in the diagram) aren't air
//have to do a descend, because fall is impossible
//this doesn't guarantee descend is possible, it just guarantees fall is impossible if (!canWalkThrough(dest.down(2))) {
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1 //if B in the diagram aren't air
} //have to do a descend, because fall is impossible
//this doesn't guarantee descend is possible, it just guarantees fall is impossible
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1
} }
// we're clear for a fall 2 // we're clear for a fall 2
// let's see how far we can fall // let's see how far we can fall
for (int fallHeight = 3; true; fallHeight++) { for (int fallHeight = 3; true; fallHeight++) {
@@ -64,15 +64,20 @@ public class MovementAscend extends Movement {
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend // Counterpoint to the above TODO ^ you should move then pillar instead of ascend
} }
@Override
public void reset() {
super.reset();
ticksWithoutPlacement = 0;
}
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
IBlockState toPlace = BlockStateInterface.get(positionsToPlace[0]); IBlockState toPlace = BlockStateInterface.get(positionsToPlace[0]);
if (!MovementHelper.canWalkOn(positionsToPlace[0], toPlace)) { if (!MovementHelper.canWalkOn(positionsToPlace[0], toPlace)) {
if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock())) { if (!context.hasThrowaway()) {
// TODO replace this check with isReplacable or similar
return COST_INF; return COST_INF;
} }
if (!context.hasThrowaway()) { if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionsToPlace[0], toPlace)) {
return COST_INF; return COST_INF;
} }
for (BlockPos against1 : against) { for (BlockPos against1 : against) {
@@ -125,9 +130,9 @@ public class MovementAscend extends Movement {
default: default:
return state; return state;
} }
if (playerFeet().equals(dest)) { if (playerFeet().equals(dest)) {
state.setStatus(MovementStatus.SUCCESS); return state.setStatus(MovementStatus.SUCCESS);
return state;
} }
if (!MovementHelper.canWalkOn(positionsToPlace[0])) { if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
@@ -141,34 +146,56 @@ public class MovementAscend extends Movement {
double faceZ = (dest.getZ() + anAgainst.getZ() + 1.0D) * 0.5D; double faceZ = (dest.getZ() + anAgainst.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true)); state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit; EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), anAgainst) && LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionsToPlace[0])) {
ticksWithoutPlacement++; LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
state.setInput(InputOverrideHandler.Input.SNEAK, true); if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionsToPlace[0])) {
if (player().isSneaking()) { ticksWithoutPlacement++;
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); state.setInput(InputOverrideHandler.Input.SNEAK, true);
if (player().isSneaking()) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
if (ticksWithoutPlacement > 20) {
// After 20 ticks without placement, we might be standing in the way, move back
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);
}
} }
if (ticksWithoutPlacement > 20) { System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);//we might be standing in the way, move back });
}
}
System.out.println("Trying to look at " + anAgainst + ", actually looking at" + LookBehaviorUtils.getSelectedBlock());
return state; return state;
} }
} }
return state.setStatus(MovementStatus.UNREACHABLE); return state.setStatus(MovementStatus.UNREACHABLE);
} }
MovementHelper.moveTowards(state, dest); MovementHelper.moveTowards(state, dest);
state.setInput(InputOverrideHandler.Input.JUMP, true);
// TODO check if the below actually helps or hurts, it's weird if (headBonkClear()) {
//double flatDistToNext = Math.abs(to.getX() - from.getX()) * Math.abs((to.getX() + 0.5D) - thePlayer.posX) + Math.abs(to.getZ() - from.getZ()) * Math.abs((to.getZ() + 0.5D) - thePlayer.posZ); return state.setInput(InputOverrideHandler.Input.JUMP, true);
//boolean pointingInCorrectDirection = MovementManager.moveTowardsBlock(to); }
//MovementManager.jumping = flatDistToNext < 1.2 && pointingInCorrectDirection;
//once we are pointing the right way and moving, start jumping
//this is slightly more efficient because otherwise we might start jumping before moving, and fall down without moving onto the block we want to jump onto
//also wait until we are close enough, because we might jump and hit our head on an adjacent block
//return Baritone.playerFeet.equals(to);
return state; int xAxis = Math.abs(src.getX() - dest.getX()); // either 0 or 1
int zAxis = Math.abs(src.getZ() - dest.getZ()); // either 0 or 1
double flatDistToNext = xAxis * Math.abs((dest.getX() + 0.5D) - player().posX) + zAxis * Math.abs((dest.getZ() + 0.5D) - player().posZ);
double sideDist = zAxis * Math.abs((dest.getX() + 0.5D) - player().posX) + xAxis * Math.abs((dest.getZ() + 0.5D) - player().posZ);
// System.out.println(flatDistToNext + " " + sideDist);
if (flatDistToNext > 1.2 || sideDist > 0.2) {
return state;
}
// Once we are pointing the right way and moving, start jumping
// This is slightly more efficient because otherwise we might start jumping before moving, and fall down without moving onto the block we want to jump onto
// Also wait until we are close enough, because we might jump and hit our head on an adjacent block
return state.setInput(InputOverrideHandler.Input.JUMP, true);
}
private boolean headBonkClear() {
BlockPos startUp = src.up(2);
for (int i = 0; i < 4; i++) {
BlockPos check = startUp.offset(EnumFacing.byHorizontalIndex(i));
if (!MovementHelper.canWalkThrough(check)) {
// We might bonk our head
return false;
}
}
return true;
} }
} }
@@ -36,6 +36,12 @@ public class MovementDescend extends Movement {
super(start, end, new BlockPos[]{end.up(2), end.up(), end}, new BlockPos[]{end.down()}); super(start, end, new BlockPos[]{end.up(2), end.up(), end}, new BlockPos[]{end.down()});
} }
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(positionsToPlace[0])) { if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
@@ -67,6 +73,7 @@ public class MovementDescend extends Movement {
default: default:
return state; return state;
} }
BlockPos playerFeet = playerFeet(); BlockPos playerFeet = playerFeet();
if (playerFeet.equals(dest)) { if (playerFeet.equals(dest)) {
if (BlockStateInterface.isLiquid(dest) || player().posY - playerFeet.getY() < 0.094) { // lilypads if (BlockStateInterface.isLiquid(dest) || player().posY - playerFeet.getY() < 0.094) { // lilypads
@@ -85,9 +92,6 @@ public class MovementDescend extends Movement {
double fromStart = Math.sqrt(x * x + z * z); double fromStart = Math.sqrt(x * x + z * z);
if (!playerFeet.equals(dest) || ab > 0.25) { if (!playerFeet.equals(dest) || ab > 0.25) {
BlockPos fakeDest = new BlockPos(dest.getX() * 2 - src.getX(), dest.getY(), dest.getZ() * 2 - src.getZ()); BlockPos fakeDest = new BlockPos(dest.getX() * 2 - src.getX(), dest.getY(), dest.getZ() * 2 - src.getZ());
double diffX2 = player().posX - (fakeDest.getX() + 0.5);
double diffZ2 = player().posZ - (fakeDest.getZ() + 0.5);
double d = Math.sqrt(diffX2 * diffX2 + diffZ2 * diffZ2);
if (numTicks++ < 20) { if (numTicks++ < 20) {
MovementHelper.moveTowards(state, fakeDest); MovementHelper.moveTowards(state, fakeDest);
if (fromStart > 1.25) { if (fromStart > 1.25) {
@@ -22,6 +22,7 @@ import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.BlockMagma; import net.minecraft.block.BlockMagma;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
@@ -29,6 +30,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
public class MovementDiagonal extends Movement { public class MovementDiagonal extends Movement {
@@ -58,12 +60,13 @@ public class MovementDiagonal extends Movement {
default: default:
return state; return state;
} }
if (playerFeet().equals(dest)) { if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS); state.setStatus(MovementState.MovementStatus.SUCCESS);
return state; return state;
} }
if (!BlockStateInterface.isLiquid(playerFeet())) { if (!BlockStateInterface.isLiquid(playerFeet())) {
player().setSprinting(true); state.setInput(InputOverrideHandler.Input.SPRINT, true);
} }
MovementHelper.moveTowards(state, dest); MovementHelper.moveTowards(state, dest);
return state; return state;
@@ -80,7 +83,7 @@ public class MovementDiagonal extends Movement {
} }
double multiplier = WALK_ONE_BLOCK_COST; double multiplier = WALK_ONE_BLOCK_COST;
// for either possible soul sand, that affects half of our walking // For either possible soul sand, that affects half of our walking
if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) { if (destWalkOn.getBlock().equals(Blocks.SOUL_SAND)) {
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2; multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
} }
@@ -94,8 +97,8 @@ public class MovementDiagonal extends Movement {
if (BlockStateInterface.get(positionsToBreak[4].down()).getBlock() instanceof BlockMagma) { if (BlockStateInterface.get(positionsToBreak[4].down()).getBlock() instanceof BlockMagma) {
return COST_INF; return COST_INF;
} }
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]); double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], true);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3]); double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], true);
if (optionA != 0 && optionB != 0) { if (optionA != 0 && optionB != 0) {
return COST_INF; return COST_INF;
} }
@@ -116,17 +119,17 @@ public class MovementDiagonal extends Movement {
} }
} }
if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) { if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) {
// ignore previous multiplier // Ignore previous multiplier
// whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water // Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// not even touching the blocks below // Not even touching the blocks below
multiplier = WALK_ONE_IN_WATER_COST; multiplier = WALK_ONE_IN_WATER_COST;
} }
if (optionA != 0 || optionB != 0) { if (optionA != 0 || optionB != 0) {
multiplier *= SQRT_2 - 0.001; // TODO tune multiplier *= SQRT_2 - 0.001; // TODO tune
} }
if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) { if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) {
// if we aren't edging around anything, and we aren't in water or soul sand // If we aren't edging around anything, and we aren't in water or soul sand
// we can sprint =D // We can sprint =D
multiplier = SPRINT_ONE_BLOCK_COST; multiplier = SPRINT_ONE_BLOCK_COST;
} }
return multiplier * SQRT_2; return multiplier * SQRT_2;
@@ -138,11 +141,11 @@ public class MovementDiagonal extends Movement {
} }
@Override @Override
public ArrayList<BlockPos> toBreak() { public List<BlockPos> toBreak() {
if (toBreakCached != null) { if (toBreakCached != null) {
return toBreakCached; return toBreakCached;
} }
ArrayList<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (int i = 4; i < 6; i++) { for (int i = 4; i < 6; i++) {
if (!MovementHelper.canWalkThrough(positionsToBreak[i])) { if (!MovementHelper.canWalkThrough(positionsToBreak[i])) {
result.add(positionsToBreak[i]); result.add(positionsToBreak[i]);
@@ -153,11 +156,11 @@ public class MovementDiagonal extends Movement {
} }
@Override @Override
public ArrayList<BlockPos> toWalkInto() { public List<BlockPos> toWalkInto() {
if (toWalkIntoCached == null) { if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>(); toWalkIntoCached = new ArrayList<>();
} }
ArrayList<BlockPos> result = new ArrayList<>(); List<BlockPos> result = new ArrayList<>();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
if (!MovementHelper.canWalkThrough(positionsToBreak[i])) { if (!MovementHelper.canWalkThrough(positionsToBreak[i])) {
result.add(positionsToBreak[i]); result.add(positionsToBreak[i]);
@@ -36,6 +36,12 @@ public class MovementDownward extends Movement {
super(start, end, new BlockPos[]{end}, new BlockPos[0]); super(start, end, new BlockPos[]{end}, new BlockPos[0]);
} }
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(dest.down())) { if (!MovementHelper.canWalkOn(dest.down())) {
@@ -47,7 +53,8 @@ public class MovementDownward extends Movement {
if (ladder) { if (ladder) {
return LADDER_DOWN_ONE_COST; return LADDER_DOWN_ONE_COST;
} else { } else {
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d); // we're standing on it, while it might be block falling, it'll be air by the time we get here in the movement
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, dest, d, false);
} }
} }
@@ -62,6 +69,7 @@ public class MovementDownward extends Movement {
default: default:
return state; return state;
} }
if (playerFeet().equals(dest)) { if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS); state.setStatus(MovementState.MovementStatus.SUCCESS);
return state; return state;
@@ -18,25 +18,20 @@
package baritone.pathing.movement.movements; package baritone.pathing.movement.movements;
import baritone.Baritone; import baritone.Baritone;
import baritone.behavior.impl.LookBehaviorUtils;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper; import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus; import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget; import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.BlockStateInterface; import baritone.utils.*;
import baritone.utils.InputOverrideHandler; import net.minecraft.block.BlockFalling;
import baritone.utils.Rotation;
import baritone.utils.Utils;
import net.minecraft.block.Block;
import net.minecraft.init.Items; import net.minecraft.init.Items;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import java.util.Optional;
public class MovementFall extends Movement { public class MovementFall extends Movement {
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET); private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
@@ -61,22 +56,29 @@ public class MovementFall extends Movement {
} }
placeBucketCost = context.placeBlockCost(); placeBucketCost = context.placeBlockCost();
} }
double frontTwo = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]); double frontThree = 0;
if (frontTwo >= COST_INF) { for (int i = 0; i < 3; i++) {
frontThree += MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false);
// don't include falling because we will check falling right after this, and if it's there it's COST_INF
if (frontThree >= COST_INF) {
return COST_INF;
}
}
if (BlockStateInterface.get(positionsToBreak[0].up()).getBlock() instanceof BlockFalling) {
return COST_INF; return COST_INF;
} }
for (int i = 2; i < positionsToBreak.length; i++) { for (int i = 3; i < positionsToBreak.length; i++) {
// TODO is this the right check here? // TODO is this the right check here?
// miningDurationTicks is all right, but shouldn't it be canWalkThrough instead? // MiningDurationTicks is all right, but shouldn't it be canWalkThrough instead?
// lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage // Lilypads (i think?) are 0 ticks to mine, but they definitely cause fall damage
// same thing for falling through water... we can't actually do that // Same thing for falling through water... we can't actually do that
// and falling through signs is possible, but they do have a mining duration, right? // And falling through signs is possible, but they do have a mining duration, right?
if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i]) > 0) { if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false) > 0) {
//can't break while falling //can't break while falling
return COST_INF; return COST_INF;
} }
} }
return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontTwo; return WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[positionsToBreak.length - 1] + placeBucketCost + frontThree;
} }
@Override @Override
@@ -90,21 +92,28 @@ public class MovementFall extends Movement {
default: default:
return state; return state;
} }
BlockPos playerFeet = playerFeet(); BlockPos playerFeet = playerFeet();
Optional<Rotation> targetRotation = Optional.empty(); Rotation targetRotation = null;
if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) { if (!BlockStateInterface.isWater(dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) {
if (!player().inventory.hasItemStack(STACK_BUCKET_WATER) || world().provider.isNether()) { // TODO check if water bucket is on hotbar or main inventory if (!player().inventory.hasItemStack(STACK_BUCKET_WATER) || world().provider.isNether()) {
state.setStatus(MovementStatus.UNREACHABLE); state.setStatus(MovementStatus.UNREACHABLE);
return state; return state;
} }
if (player().posY - dest.getY() < mc.playerController.getBlockReachDistance()) { if (player().posY - dest.getY() < mc.playerController.getBlockReachDistance()) {
player().inventory.currentItem = player().inventory.getSlotFor(STACK_BUCKET_WATER); player().inventory.currentItem = player().inventory.getSlotFor(STACK_BUCKET_WATER);
targetRotation = LookBehaviorUtils.reachable((BlockStateInterface.get(dest).getCollisionBoundingBox(mc.world, dest) == Block.NULL_AABB) ? dest : dest.down());
targetRotation = new Rotation(player().rotationYaw, 90.0F);
RayTraceResult trace = RayTraceUtils.simulateRayTrace(player().rotationYaw, 90.0F);
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
} }
} }
if (targetRotation.isPresent()) { if (targetRotation != null) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true) state.setTarget(new MovementTarget(targetRotation, true));
.setTarget(new MovementTarget(targetRotation.get(), true));
} else { } else {
state.setTarget(new MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.getBlockPosCenter(dest)), false)); state.setTarget(new MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.getBlockPosCenter(dest)), false));
} }
@@ -38,6 +38,12 @@ public class MovementPillar extends Movement {
super(start, end, new BlockPos[]{start.up(2)}, new BlockPos[]{start}); super(start, end, new BlockPos[]{start.up(2)}, new BlockPos[]{start});
} }
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src).getBlock(); Block fromDown = BlockStateInterface.get(src).getBlock();
@@ -109,6 +115,7 @@ public class MovementPillar extends Movement {
default: default:
return state; return state;
} }
IBlockState fromDown = BlockStateInterface.get(src); IBlockState fromDown = BlockStateInterface.get(src);
boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine; boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine;
boolean vine = fromDown.getBlock() instanceof BlockVine; boolean vine = fromDown.getBlock() instanceof BlockVine;
@@ -117,57 +124,68 @@ public class MovementPillar extends Movement {
Utils.getBlockPosCenter(positionsToPlace[0]), Utils.getBlockPosCenter(positionsToPlace[0]),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)), true)); new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)), true));
} }
EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
boolean blockIsThere = MovementHelper.canWalkOn(src) || ladder; boolean blockIsThere = MovementHelper.canWalkOn(src) || ladder;
if (ladder) { if (ladder) {
BlockPos against = vine ? getAgainst(src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite()); BlockPos against = vine ? getAgainst(src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite());
if (against == null) { if (against == null) {
displayChatMessageRaw("Unable to climb vines"); displayChatMessageRaw("Unable to climb vines");
state.setStatus(MovementState.MovementStatus.UNREACHABLE); return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state;
} }
if (playerFeet().equals(against.up()) || playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS); if (playerFeet().equals(against.up()) || playerFeet().equals(dest))
return state; return state.setStatus(MovementState.MovementStatus.SUCCESS);
/*
if (thePlayer.getPosition0().getX() != from.getX() || thePlayer.getPosition0().getZ() != from.getZ()) {
Baritone.moveTowardsBlock(from);
} }
/*if (thePlayer.getPosition0().getX() != from.getX() || thePlayer.getPosition0().getZ() != from.getZ()) { */
Baritone.moveTowardsBlock(from);
}*/
MovementHelper.moveTowards(state, against); MovementHelper.moveTowards(state, against);
return state; return state;
} else { } else {
if (!MovementHelper.throwaway(true)) {//get ready to place a throwaway block // Get ready to place a throwaway block
if (!MovementHelper.throwaway(true)) {
state.setStatus(MovementState.MovementStatus.UNREACHABLE); state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state; return state;
} }
numTicks++; numTicks++;
state.setInput(InputOverrideHandler.Input.JUMP, thePlayer.posY < dest.getY()); //if our Y coordinate is above our goal, stop jumping // If our Y coordinate is above our goal, stop jumping
state.setInput(InputOverrideHandler.Input.JUMP, player().posY < dest.getY());
state.setInput(InputOverrideHandler.Input.SNEAK, true); state.setInput(InputOverrideHandler.Input.SNEAK, true);
//otherwise jump
// Otherwise jump
if (numTicks > 40) { if (numTicks > 40) {
double diffX = thePlayer.posX - (dest.getX() + 0.5); double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = thePlayer.posZ - (dest.getZ() + 0.5); double diffZ = player().posZ - (dest.getZ() + 0.5);
double dist = Math.sqrt(diffX * diffX + diffZ * diffZ); double dist = Math.sqrt(diffX * diffX + diffZ * diffZ);
if (dist > 0.17) {//why 0.17? because it seemed like a good number, that's why if (dist > 0.17) {//why 0.17? because it seemed like a good number, that's why
//[explanation added after baritone port lol] also because it needs to be less than 0.2 because of the 0.3 sneak limit //[explanation added after baritone port lol] also because it needs to be less than 0.2 because of the 0.3 sneak limit
//and 0.17 is reasonably less than 0.2 //and 0.17 is reasonably less than 0.2
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);//if it's been more than forty ticks of trying to jump and we aren't done yet, go forward, maybe we are stuck
// If it's been more than forty ticks of trying to jump and we aren't done yet, go forward, maybe we are stuck
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
} }
} }
if (!blockIsThere) { if (!blockIsThere) {
Block fr = BlockStateInterface.get(src).getBlock(); Block fr = BlockStateInterface.get(src).getBlock();
if (!(fr instanceof BlockAir || fr.isReplaceable(Minecraft.getMinecraft().world, src))) { if (!(fr instanceof BlockAir || fr.isReplaceable(Minecraft.getMinecraft().world, src))) {
state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true); state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
blockIsThere = false; blockIsThere = false;
} else if (Minecraft.getMinecraft().player.isSneaking()) { } else if (Minecraft.getMinecraft().player.isSneaking()) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);//constantly right click state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
} }
} }
} }
if (playerFeet().equals(dest) && blockIsThere) {//if we are at our goal and the block below us is placed
state.setStatus(MovementState.MovementStatus.SUCCESS); // If we are at our goal and the block below us is placed
return state;//we are done if (playerFeet().equals(dest) && blockIsThere) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
} }
return state; return state;
} }
} }
@@ -25,10 +25,7 @@ import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler; import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils; import baritone.utils.Utils;
import net.minecraft.block.Block; import net.minecraft.block.*;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.block.state.IBlockState; import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks; import net.minecraft.init.Blocks;
@@ -66,6 +63,12 @@ public class MovementTraverse extends Movement {
//note: do NOT add ability to place against .down().down() //note: do NOT add ability to place against .down().down()
} }
@Override
public void reset() {
super.reset();
wasTheBridgeBlockAlwaysThere = true;
}
@Override @Override
protected double calculateCost(CalculationContext context) { protected double calculateCost(CalculationContext context) {
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
@@ -85,15 +88,15 @@ public class MovementTraverse extends Movement {
} }
if (MovementHelper.canWalkThrough(positionsToBreak[0], pb0) && MovementHelper.canWalkThrough(positionsToBreak[1], pb1)) { if (MovementHelper.canWalkThrough(positionsToBreak[0], pb0) && MovementHelper.canWalkThrough(positionsToBreak[1], pb1)) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) { if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) {
// if there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing // If there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing
// we can sprint =D // We can sprint =D
WC = SPRINT_ONE_BLOCK_COST; WC = SPRINT_ONE_BLOCK_COST;
} }
return WC; return WC;
} }
//double hardness1 = blocksToBreak[0].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[0]); // double hardness1 = blocksToBreak[0].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[0]);
//double hardness2 = blocksToBreak[1].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[1]); // double hardness2 = blocksToBreak[1].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[1]);
//Out.log("Can't walk through " + blocksToBreak[0] + " (hardness" + hardness1 + ") or " + blocksToBreak[1] + " (hardness " + hardness2 + ")"); // Out.log("Can't walk through " + blocksToBreak[0] + " (hardness" + hardness1 + ") or " + blocksToBreak[1] + " (hardness " + hardness2 + ")");
return WC + getTotalHardnessOfBlocksToBreak(context); return WC + getTotalHardnessOfBlocksToBreak(context);
} else {//this is a bridge, so we need to place a block } else {//this is a bridge, so we need to place a block
Block srcDown = BlockStateInterface.get(src.down()).getBlock(); Block srcDown = BlockStateInterface.get(src.down()).getBlock();
@@ -101,7 +104,7 @@ public class MovementTraverse extends Movement {
return COST_INF; return COST_INF;
} }
IBlockState pp0 = BlockStateInterface.get(positionsToPlace[0]); IBlockState pp0 = BlockStateInterface.get(positionsToPlace[0]);
if (pp0.getBlock().equals(Blocks.AIR) || (!BlockStateInterface.isWater(pp0.getBlock()) && pp0.getBlock().isReplaceable(Minecraft.getMinecraft().world, positionsToPlace[0]))) { if (pp0.getBlock().equals(Blocks.AIR) || (!BlockStateInterface.isWater(pp0.getBlock()) && MovementHelper.isReplacable(positionsToPlace[0], pp0))) {
if (!context.hasThrowaway()) { if (!context.hasThrowaway()) {
return COST_INF; return COST_INF;
} }
@@ -118,7 +121,7 @@ public class MovementTraverse extends Movement {
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context); return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
} }
return COST_INF; return COST_INF;
//Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock()); // Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock());
} }
} }
@@ -133,27 +136,44 @@ public class MovementTraverse extends Movement {
default: default:
return state; return state;
} }
Block fd = BlockStateInterface.get(src.down()).getBlock(); Block fd = BlockStateInterface.get(src.down()).getBlock();
boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine; boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine;
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]); IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]); IBlockState pb1 = BlockStateInterface.get(positionsToBreak[1]);
boolean door = BlockStateInterface.get(src).getBlock() instanceof BlockDoor || pb0.getBlock() instanceof BlockDoor || pb1.getBlock() instanceof BlockDoor;
boolean door = pb0.getBlock() instanceof BlockDoor || pb1.getBlock() instanceof BlockDoor;
if (door) { if (door) {
boolean isDoorActuallyBlockingUs = false; boolean isDoorActuallyBlockingUs = false;
Block srcBlock = BlockStateInterface.get(src).getBlock(); if (pb0.getBlock() instanceof BlockDoor && !MovementHelper.isDoorPassable(src, dest)) {
if (srcBlock instanceof BlockDoor && !MovementHelper.isDoorPassable(src, dest)) {
isDoorActuallyBlockingUs = true; isDoorActuallyBlockingUs = true;
} else if (pb1.getBlock() instanceof BlockDoor && !MovementHelper.isDoorPassable(dest, src)) { } else if (pb1.getBlock() instanceof BlockDoor && !MovementHelper.isDoorPassable(dest, src)) {
isDoorActuallyBlockingUs = true; isDoorActuallyBlockingUs = true;
} }
if (isDoorActuallyBlockingUs) { if (isDoorActuallyBlockingUs) {
if (!(Blocks.IRON_DOOR.equals(srcBlock) || Blocks.IRON_DOOR.equals(pb0.getBlock()) || Blocks.IRON_DOOR.equals(pb1.getBlock()))) { if (!(Blocks.IRON_DOOR.equals(pb0.getBlock()) || Blocks.IRON_DOOR.equals(pb1.getBlock()))) {
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(positionsToBreak[0], world())), true)); state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(positionsToBreak[0], world())), true));
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
return state; return state;
} }
} }
} }
if (pb0.getBlock() instanceof BlockFenceGate || pb1.getBlock() instanceof BlockFenceGate) {
BlockPos blocked = null;
if (!MovementHelper.isGatePassable(positionsToBreak[0], src.up())) {
blocked = positionsToBreak[0];
} else if (!MovementHelper.isGatePassable(positionsToBreak[1], src)) {
blocked = positionsToBreak[1];
}
if (blocked != null) {
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(blocked, world())), true));
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
return state;
}
}
boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(positionsToPlace[0]) || ladder; boolean isTheBridgeBlockThere = MovementHelper.canWalkOn(positionsToPlace[0]) || ladder;
BlockPos whereAmI = playerFeet(); BlockPos whereAmI = playerFeet();
if (whereAmI.getY() != dest.getY() && !ladder) { if (whereAmI.getY() != dest.getY() && !ladder) {
@@ -163,13 +183,14 @@ public class MovementTraverse extends Movement {
} }
return state; return state;
} }
if (isTheBridgeBlockThere) { if (isTheBridgeBlockThere) {
if (playerFeet().equals(dest)) { if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS); state.setStatus(MovementState.MovementStatus.SUCCESS);
return state; return state;
} }
if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) { if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) {
player().setSprinting(true); state.setInput(InputOverrideHandler.Input.SPRINT, true);
} }
Block destDown = BlockStateInterface.get(dest.down()).getBlock(); Block destDown = BlockStateInterface.get(dest.down()).getBlock();
if (ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) { if (ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
@@ -195,18 +216,18 @@ public class MovementTraverse extends Movement {
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit; EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), against1) && Minecraft.getMinecraft().player.isSneaking()) { if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), against1) && Minecraft.getMinecraft().player.isSneaking()) {
if (LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionsToPlace[0])) { if (LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionsToPlace[0])) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
} else { } else {
// Out.gui("Wrong. " + side + " " + LookBehaviorUtils.getSelectedBlock().get().offset(side) + " " + positionsToPlace[0], Out.Mode.Debug); // Out.gui("Wrong. " + side + " " + LookBehaviorUtils.getSelectedBlock().get().offset(side) + " " + positionsToPlace[0], Out.Mode.Debug);
} }
} }
System.out.println("Trying to look at " + against1 + ", actually looking at" + LookBehaviorUtils.getSelectedBlock()); System.out.println("Trying to look at " + against1 + ", actually looking at" + LookBehaviorUtils.getSelectedBlock());
return state; return state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
} }
} }
state.setInput(InputOverrideHandler.Input.SNEAK, true); state.setInput(InputOverrideHandler.Input.SNEAK, true);
if (whereAmI.equals(dest)) { if (whereAmI.equals(dest)) {
// if we are in the block that we are trying to get to, we are sneaking over air and we need to place a block beneath us against the one we just walked off of // If we are in the block that we are trying to get to, we are sneaking over air and we need to place a block beneath us against the one we just walked off of
// Out.log(from + " " + to + " " + faceX + "," + faceY + "," + faceZ + " " + whereAmI); // Out.log(from + " " + to + " " + faceX + "," + faceY + "," + faceZ + " " + whereAmI);
if (!MovementHelper.throwaway(true)) {// get ready to place a throwaway block if (!MovementHelper.throwaway(true)) {// get ready to place a throwaway block
displayChatMessageRaw("bb pls get me some blocks. dirt or cobble"); displayChatMessageRaw("bb pls get me some blocks. dirt or cobble");
@@ -146,7 +146,7 @@ public interface IPath extends Helper {
} }
double factor = Baritone.settings().pathCutoffFactor.get(); double factor = Baritone.settings().pathCutoffFactor.get();
int newLength = (int) (length() * factor); int newLength = (int) (length() * factor);
displayChatMessageRaw("Static cutoff " + length() + " to " + newLength); //displayChatMessageRaw("Static cutoff " + length() + " to " + newLength);
return new CutoffPath(this, newLength); return new CutoffPath(this, newLength);
} }
} }
@@ -22,6 +22,9 @@ import baritone.event.events.TickEvent;
import baritone.pathing.movement.ActionCosts; import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementState; import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.movements.MovementDescend;
import baritone.pathing.movement.movements.MovementDiagonal;
import baritone.pathing.movement.movements.MovementTraverse;
import baritone.utils.BlockStateInterface; import baritone.utils.BlockStateInterface;
import baritone.utils.Helper; import baritone.utils.Helper;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
@@ -90,7 +93,11 @@ public class PathExecutor implements Helper {
for (int i = 0; i < pathPosition - 2 && i < path.length(); i++) {//this happens for example when you lag out and get teleported back a couple blocks for (int i = 0; i < pathPosition - 2 && i < path.length(); i++) {//this happens for example when you lag out and get teleported back a couple blocks
if (whereAmI.equals(path.positions().get(i))) { if (whereAmI.equals(path.positions().get(i))) {
displayChatMessageRaw("Skipping back " + (pathPosition - i) + " steps, to " + i); displayChatMessageRaw("Skipping back " + (pathPosition - i) + " steps, to " + i);
int previousPos = pathPosition;
pathPosition = Math.max(i - 1, 0); // previous step might not actually be done pathPosition = Math.max(i - 1, 0); // previous step might not actually be done
for (int j = pathPosition; j <= previousPos; j++) {
path.movements().get(j).reset();
}
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys(); Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return false; return false;
} }
@@ -207,6 +214,15 @@ public class PathExecutor implements Helper {
if (costEstimateIndex == null || costEstimateIndex != pathPosition) { if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition; costEstimateIndex = pathPosition;
currentMovementInitialCostEstimate = currentCost; // do this only once, when the movement starts currentMovementInitialCostEstimate = currentCost; // do this only once, when the movement starts
for (int i = 1; i < Baritone.settings().costVerificationLookahead.get() && pathPosition + i < path.length() - 1; i++) {
if (path.movements().get(pathPosition + i).recalculateCost() >= ActionCosts.COST_INF) {
displayChatMessageRaw("Something has changed in the world and a future movement has become impossible. Cancelling.");
pathPosition = path.length() + 3;
failed = true;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return true;
}
}
} }
MovementState.MovementStatus movementStatus = movement.update(); MovementState.MovementStatus movementStatus = movement.update();
if (movementStatus == UNREACHABLE || movementStatus == FAILED) { if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
@@ -224,6 +240,7 @@ public class PathExecutor implements Helper {
onTick(event); onTick(event);
return true; return true;
} else { } else {
sprintIfRequested();
ticksOnCurrent++; ticksOnCurrent++;
if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) { if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) {
// only fail if the total time has exceeded the initial estimate // only fail if the total time has exceeded the initial estimate
@@ -241,6 +258,59 @@ public class PathExecutor implements Helper {
return false; // movement is in progress return false; // movement is in progress
} }
private void sprintIfRequested() {
if (!Baritone.settings().allowSprint.get()) {
player().setSprinting(false);
return;
}
if (Baritone.INSTANCE.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) {
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
Movement movement = path.movements().get(pathPosition);
if (movement instanceof MovementDescend && pathPosition < path.length() - 2) {
Movement next = path.movements().get(pathPosition + 1);
if (next instanceof MovementDescend) {
if (next.getDirection().equals(movement.getDirection())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementTraverse) {
if (next.getDirection().down().equals(movement.getDirection())) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
if (next instanceof MovementDiagonal && Baritone.settings().allowOvershootDiagonalDescend.get()) {
if (playerFeet().equals(movement.getDest())) {
pathPosition++;
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
}
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
//displayChatMessageRaw("Turning off sprinting " + movement + " " + next + " " + movement.getDirection() + " " + next.getDirection().down() + " " + next.getDirection().down().equals(movement.getDirection()));
}
player().setSprinting(false);
}
public int getPosition() { public int getPosition() {
return pathPosition; return pathPosition;
} }
@@ -0,0 +1,52 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
/**
* @author Brady
* @since 8/25/2018
*/
public final class BlockBreakHelper implements Helper {
private BlockBreakHelper() {}
/**
* The last block that we tried to break, if this value changes
* between attempts, then we re-initialize the breaking process.
*/
private static BlockPos lastBlock;
public static void tryBreakBlock(BlockPos pos, EnumFacing side) {
if (!pos.equals(lastBlock)) {
mc.playerController.clickBlock(pos, side);
}
if (mc.playerController.onPlayerDamageBlock(pos, side)) {
mc.player.swingArm(EnumHand.MAIN_HAND);
}
lastBlock = pos;
}
public static void stopBreakingBlock() {
mc.playerController.resetBlockRemoving();
lastBlock = null;
}
}
@@ -18,7 +18,7 @@
package baritone.utils; package baritone.utils;
import baritone.Baritone; import baritone.Baritone;
import baritone.chunk.CachedWorld; import baritone.chunk.WorldData;
import baritone.chunk.WorldProvider; import baritone.chunk.WorldProvider;
import net.minecraft.block.Block; import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling; import net.minecraft.block.BlockFalling;
@@ -42,16 +42,15 @@ public class BlockStateInterface implements Helper {
return chunk.getBlockState(pos); return chunk.getBlockState(pos);
} }
} }
if (Baritone.settings().chunkCaching.get()) { WorldData world = WorldProvider.INSTANCE.getCurrentWorld();
CachedWorld world = WorldProvider.INSTANCE.getCurrentWorld().cache; if (world != null) {
if (world != null) { IBlockState type = world.cache.getBlock(pos);
IBlockState type = world.getBlock(pos); if (type != null) {
if (type != null) { return type;
return type;
}
} }
} }
return Blocks.AIR.getDefaultState(); return Blocks.AIR.getDefaultState();
} }
@@ -21,23 +21,23 @@ import baritone.Baritone;
import baritone.Settings; import baritone.Settings;
import baritone.behavior.Behavior; import baritone.behavior.Behavior;
import baritone.behavior.impl.PathingBehavior; import baritone.behavior.impl.PathingBehavior;
import baritone.chunk.ChunkPacker;
import baritone.chunk.Waypoint;
import baritone.chunk.WorldProvider;
import baritone.event.events.ChatEvent; import baritone.event.events.ChatEvent;
import baritone.map.Map; import baritone.map.Map;
import baritone.pathing.calc.AStarPathFinder; import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.goals.Goal; import baritone.pathing.goals.*;
import baritone.pathing.goals.GoalBlock;
import baritone.pathing.goals.GoalXZ;
import baritone.pathing.goals.GoalYLevel;
import baritone.pathing.movement.ActionCosts; import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext; import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement; import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos; import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList; import java.util.*;
import java.util.Arrays; import java.util.stream.Collectors;
import java.util.Comparator;
import java.util.List;
public class ExampleBaritoneControl extends Behavior { public class ExampleBaritoneControl extends Behavior {
public static ExampleBaritoneControl INSTANCE = new ExampleBaritoneControl(); public static ExampleBaritoneControl INSTANCE = new ExampleBaritoneControl();
@@ -56,7 +56,10 @@ public class ExampleBaritoneControl extends Behavior {
return; return;
} }
String msg = event.getMessage(); String msg = event.getMessage();
if (msg.startsWith("/")) { if (Baritone.settings().prefix.get()) {
if (!msg.startsWith("#")) {
return;
}
msg = msg.substring(1); msg = msg.substring(1);
} }
if (msg.toLowerCase().startsWith("goal")) { if (msg.toLowerCase().startsWith("goal")) {
@@ -107,6 +110,79 @@ public class ExampleBaritoneControl extends Behavior {
displayChatMessageRaw("ok canceled"); displayChatMessageRaw("ok canceled");
return; return;
} }
if (msg.toLowerCase().equals("invert")) {
Goal goal = PathingBehavior.INSTANCE.getGoal();
BlockPos runAwayFrom;
if (goal instanceof GoalXZ) {
runAwayFrom = new BlockPos(((GoalXZ) goal).getX(), 0, ((GoalXZ) goal).getZ());
} else if (goal instanceof GoalBlock) {
runAwayFrom = ((GoalBlock) goal).getGoalPos();
} else {
displayChatMessageRaw("Goal must be GoalXZ or GoalBlock to invert");
displayChatMessageRaw("Inverting goal of player feet");
runAwayFrom = playerFeet();
}
PathingBehavior.INSTANCE.setGoal(new GoalRunAway(1, runAwayFrom) {
@Override
public boolean isInGoal(BlockPos pos) {
return false;
}
});
PathingBehavior.INSTANCE.path();
event.cancel();
return;
}
if (msg.toLowerCase().equals("reloadall")) {
WorldProvider.INSTANCE.getCurrentWorld().cache.reloadAllFromDisk();
displayChatMessageRaw("ok");
event.cancel();
return;
}
if (msg.toLowerCase().equals("saveall")) {
WorldProvider.INSTANCE.getCurrentWorld().cache.save();
displayChatMessageRaw("ok");
event.cancel();
return;
}
if (msg.toLowerCase().startsWith("find")) {
String blockType = msg.toLowerCase().substring(4).trim();
LinkedList<BlockPos> locs = WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(blockType, 1, 4);
displayChatMessageRaw("Have " + locs.size() + " locations");
for (BlockPos pos : locs) {
Block actually = BlockStateInterface.get(pos).getBlock();
if (!ChunkPacker.blockToString(actually).equalsIgnoreCase(blockType)) {
System.out.println("Was looking for " + blockType + " but actually found " + actually + " " + ChunkPacker.blockToString(actually));
}
}
event.cancel();
return;
}
if (msg.toLowerCase().startsWith("mine")) {
String blockType = msg.toLowerCase().substring(4).trim();
List<BlockPos> locs = new ArrayList<>(WorldProvider.INSTANCE.getCurrentWorld().cache.getLocationsOf(blockType, 1, 1));
if (locs.isEmpty()) {
displayChatMessageRaw("No locations known");
event.cancel();
return;
}
BlockPos playerFeet = playerFeet();
locs.sort(Comparator.comparingDouble(playerFeet::distanceSq));
// remove any that are within loaded chunks that aren't actually what we want
locs.removeAll(locs.stream()
.filter(pos -> !(world().getChunk(pos) instanceof EmptyChunk))
.filter(pos -> !ChunkPacker.blockToString(BlockStateInterface.get(pos).getBlock()).equalsIgnoreCase(blockType))
.collect(Collectors.toList()));
if (locs.size() > 30) {
displayChatMessageRaw("Pathing to any of closest 30");
locs = locs.subList(0, 30);
}
PathingBehavior.INSTANCE.setGoal(new GoalComposite(locs.stream().map(GoalTwoBlocks::new).toArray(Goal[]::new)));
PathingBehavior.INSTANCE.path();
event.cancel();
return;
}
if (msg.toLowerCase().startsWith("thisway")) { if (msg.toLowerCase().startsWith("thisway")) {
Goal goal = GoalXZ.fromDirection(playerFeetAsVec(), player().rotationYaw, Double.parseDouble(msg.substring(7).trim())); Goal goal = GoalXZ.fromDirection(playerFeetAsVec(), player().rotationYaw, Double.parseDouble(msg.substring(7).trim()));
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
@@ -114,18 +190,90 @@ public class ExampleBaritoneControl extends Behavior {
event.cancel(); event.cancel();
return; return;
} }
if (msg.toLowerCase().equals("spawn")) { if (msg.toLowerCase().startsWith("list") || msg.toLowerCase().startsWith("get ") || msg.toLowerCase().startsWith("show")) {
BlockPos spawnPoint = player().getBedLocation(); String waypointType = msg.toLowerCase().substring(4).trim();
// for some reason the default spawnpoint is underground sometimes if (waypointType.endsWith("s")) {
Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getY()); // for example, "show deaths"
waypointType = waypointType.substring(0, waypointType.length() - 1);
}
Waypoint.Tag tag = Waypoint.TAG_MAP.get(waypointType);
if (tag == null) {
displayChatMessageRaw("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
event.cancel();
return;
}
Set<Waypoint> waypoints = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getByTag(tag);
// might as well show them from oldest to newest
List<Waypoint> sorted = new ArrayList<>(waypoints);
sorted.sort(Comparator.comparingLong(Waypoint::creationTimestamp));
displayChatMessageRaw("Waypoints under tag " + tag + ":");
for (Waypoint waypoint : sorted) {
displayChatMessageRaw(waypoint.toString());
}
event.cancel();
return;
}
if (msg.toLowerCase().startsWith("goto")) {
String waypointType = msg.toLowerCase().substring(4).trim();
if (waypointType.endsWith("s")) {
// for example, "show deaths"
waypointType = waypointType.substring(0, waypointType.length() - 1);
}
Waypoint.Tag tag = Waypoint.TAG_MAP.get(waypointType);
if (tag == null) {
displayChatMessageRaw("Not a valid tag. Tags are: " + Arrays.asList(Waypoint.Tag.values()).toString().toLowerCase());
event.cancel();
return;
}
Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(tag);
if (waypoint == null) {
displayChatMessageRaw("None saved for tag " + tag);
event.cancel();
return;
}
Goal goal = new GoalBlock(waypoint.location);
PathingBehavior.INSTANCE.setGoal(goal); PathingBehavior.INSTANCE.setGoal(goal);
displayChatMessageRaw("Goal: " + goal); PathingBehavior.INSTANCE.path();
event.cancel();
return;
}
if (msg.toLowerCase().equals("spawn") || msg.toLowerCase().equals("bed")) {
Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(Waypoint.Tag.BED);
if (waypoint == null) {
BlockPos spawnPoint = player().getBedLocation();
// for some reason the default spawnpoint is underground sometimes
Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getZ());
displayChatMessageRaw("spawn not saved, defaulting to world spawn. set goal to " + goal);
PathingBehavior.INSTANCE.setGoal(goal);
} else {
Goal goal = new GoalBlock(waypoint.location);
PathingBehavior.INSTANCE.setGoal(goal);
displayChatMessageRaw("Set goal to most recent bed " + goal);
}
event.cancel();
return;
}
if (msg.toLowerCase().equals("sethome")) {
WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("", Waypoint.Tag.HOME, playerFeet()));
displayChatMessageRaw("Saved. Say home to set goal.");
event.cancel();
return;
}
if (msg.toLowerCase().equals("home")) {
Waypoint waypoint = WorldProvider.INSTANCE.getCurrentWorld().waypoints.getMostRecentByTag(Waypoint.Tag.HOME);
if (waypoint == null) {
displayChatMessageRaw("home not saved");
} else {
Goal goal = new GoalBlock(waypoint.location);
PathingBehavior.INSTANCE.setGoal(goal);
displayChatMessageRaw("Set goal to saved home " + goal);
}
event.cancel(); event.cancel();
return; return;
} }
if (msg.toLowerCase().equals("costs")) { if (msg.toLowerCase().equals("costs")) {
Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext()); Movement[] movements = AStarPathFinder.getConnectedPositions(new BetterBlockPos(playerFeet()), new CalculationContext());
ArrayList<Movement> moves = new ArrayList<>(Arrays.asList(movements)); List<Movement> moves = new ArrayList<>(Arrays.asList(movements));
moves.sort(Comparator.comparingDouble(movement -> movement.getCost(new CalculationContext()))); moves.sort(Comparator.comparingDouble(movement -> movement.getCost(new CalculationContext())));
for (Movement move : moves) { for (Movement move : moves) {
String[] parts = move.getClass().toString().split("\\."); String[] parts = move.getClass().toString().split("\\.");
+7 -13
View File
@@ -20,16 +20,12 @@ package baritone.utils;
import baritone.Baritone; import baritone.Baritone;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP; import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiNewChat;
import net.minecraft.client.gui.GuiUtilRenderComponents;
import net.minecraft.client.multiplayer.WorldClient; import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d; import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString; import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import java.util.List;
/** /**
* @author Brady * @author Brady
@@ -37,6 +33,8 @@ import java.util.List;
*/ */
public interface Helper { public interface Helper {
ITextComponent MESSAGE_PREFIX = new TextComponentString("§5[§dBaritone§5]§7");
Minecraft mc = Minecraft.getMinecraft(); Minecraft mc = Minecraft.getMinecraft();
default EntityPlayerSP player() { default EntityPlayerSP player() {
@@ -73,14 +71,10 @@ public interface Helper {
System.out.println(message); System.out.println(message);
return; return;
} }
GuiNewChat gui = mc.ingameGUI.getChatGUI();
int normalMaxWidth = MathHelper.floor((float) gui.getChatWidth() / gui.getChatScale());
int widthWithStyleFormat = normalMaxWidth - 2;
List<ITextComponent> list = GuiUtilRenderComponents.splitText(new TextComponentString("§5[§dBaritone§5]§7 " + message), widthWithStyleFormat,
this.mc.fontRenderer, false, true);
for (ITextComponent component : list) {
gui.printChatMessage(new TextComponentString("§7" + component.getUnformattedText())); ITextComponent component = MESSAGE_PREFIX.createCopy();
} component.getStyle().setColor(TextFormatting.GRAY);
component.appendSibling(new TextComponentString(" " + message));
mc.ingameGUI.getChatGUI().printChatMessage(component);
} }
} }
@@ -84,8 +84,6 @@ public final class InputOverrideHandler implements Helper {
* @param forced Whether or not the state is being forced * @param forced Whether or not the state is being forced
*/ */
public final void setInputForceState(Input input, boolean forced) { public final void setInputForceState(Input input, boolean forced) {
if (!forced)
System.out.println(input);
inputForceStateMap.put(input.getKeyBinding(), forced); inputForceStateMap.put(input.getKeyBinding(), forced);
} }
@@ -0,0 +1,47 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
import net.minecraft.util.math.RayTraceResult;
/**
* @author Brady
* @since 8/25/2018
*/
public final class RayTraceUtils implements Helper {
private RayTraceUtils() {}
public static RayTraceResult simulateRayTrace(float yaw, float pitch) {
RayTraceResult oldTrace = mc.objectMouseOver;
float oldYaw = mc.player.rotationYaw;
float oldPitch = mc.player.rotationPitch;
mc.player.rotationYaw = yaw;
mc.player.rotationPitch = pitch;
mc.entityRenderer.getMouseOver(1.0F);
RayTraceResult result = mc.objectMouseOver;
mc.objectMouseOver = oldTrace;
mc.player.rotationYaw = oldYaw;
mc.player.rotationPitch = oldPitch;
return result;
}
}
+21 -3
View File
@@ -69,7 +69,13 @@ public class ToolSet implements Helper {
* The values in this map are *not* hotbar slots indexes, they need to be looked up in slots * The values in this map are *not* hotbar slots indexes, they need to be looked up in slots
* in order to be converted into hotbar slots. * in order to be converted into hotbar slots.
*/ */
private Map<Block, Byte> cache = new HashMap<>(); private Map<Block, Byte> slotCache = new HashMap<>();
/**
* A cache mapping a {@link IBlockState} to how long it will take to break
* with this toolset, given the optimum tool is used.
*/
private Map<IBlockState, Double> breakStrengthCache = new HashMap<>();
/** /**
* Create a toolset from the current player's inventory (but don't calculate any hardness values just yet) * Create a toolset from the current player's inventory (but don't calculate any hardness values just yet)
@@ -96,7 +102,7 @@ public class ToolSet implements Helper {
* @return get which tool on the hotbar is best for mining it * @return get which tool on the hotbar is best for mining it
*/ */
public Item getBestTool(IBlockState state) { public Item getBestTool(IBlockState state) {
return tools.get(cache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state))); return tools.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
} }
/** /**
@@ -129,7 +135,7 @@ public class ToolSet implements Helper {
* @return a byte indicating which hotbar slot worked best * @return a byte indicating which hotbar slot worked best
*/ */
public byte getBestSlot(IBlockState state) { public byte getBestSlot(IBlockState state) {
return slots.get(cache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state))); return slots.get(slotCache.computeIfAbsent(state.getBlock(), block -> getBestToolIndex(state)));
} }
/** /**
@@ -140,6 +146,18 @@ public class ToolSet implements Helper {
* @return how long it would take in ticks * @return how long it would take in ticks
*/ */
public double getStrVsBlock(IBlockState state, BlockPos pos) { public double getStrVsBlock(IBlockState state, BlockPos pos) {
return this.breakStrengthCache.computeIfAbsent(state, s -> calculateStrVsBlock(s, pos));
}
/**
* Calculates how long would it take to mine the specified block given the best tool
* in this toolset is used.
*
* @param state the blockstate to be mined
* @param pos the blockpos to be mined
* @return how long it would take in ticks
*/
private double calculateStrVsBlock(IBlockState state, BlockPos pos) {
// Calculate the slot with the best item // Calculate the slot with the best item
byte slot = this.getBestSlot(state); byte slot = this.getBestSlot(state);
+2 -2
View File
@@ -1,13 +1,14 @@
{ {
"required": true, "required": true,
"package": "baritone.launch.mixins", "package": "baritone.launch.mixins",
"refmap": "mixins.client.refmap.json", "refmap": "mixins.baritone.refmap.json",
"compatibilityLevel": "JAVA_8", "compatibilityLevel": "JAVA_8",
"verbose": false, "verbose": false,
"injectors": { "injectors": {
"maxShiftBy": 2 "maxShiftBy": 2
}, },
"client": [ "client": [
"MixinBlockPos",
"MixinEntity", "MixinEntity",
"MixinEntityPlayerSP", "MixinEntityPlayerSP",
"MixinEntityRenderer", "MixinEntityRenderer",
@@ -16,7 +17,6 @@
"MixinGuiScreen", "MixinGuiScreen",
"MixinInventoryPlayer", "MixinInventoryPlayer",
"MixinKeyBinding", "MixinKeyBinding",
"MixinMain",
"MixinMinecraft", "MixinMinecraft",
"MixinNetHandlerPlayClient", "MixinNetHandlerPlayClient",
"MixinNetworkManager", "MixinNetworkManager",
@@ -0,0 +1,47 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.chunk;
import org.junit.Test;
import static junit.framework.TestCase.assertEquals;
public class CachedRegionTest {
@Test
public void blockPosSaving() {
for (int x = 0; x < 16; x++) {
for (int z = 0; z < 16; z++) {
for (int y = 0; y < 256; y++) {
byte part1 = (byte) (z << 4 | x);
byte part2 = (byte) (y);
byte xz = part1;
int X = xz & 0x0f;
int Z = (xz >>> 4) & 0x0f;
int Y = part2 & 0xff;
if (x != X || y != Y || z != Z) {
System.out.println(x + " " + X + " " + y + " " + Y + " " + z + " " + Z);
}
assertEquals(x, X);
assertEquals(y, Y);
assertEquals(z, Z);
}
}
}
}
}