Merge branch 'master' into mapping

This commit is contained in:
Howard Stark 2018-08-26 23:32:12 -07:00
commit d6c766fb66
No known key found for this signature in database
GPG Key ID: 9FA4E350B33067F3
50 changed files with 1662 additions and 440 deletions

View File

@ -1,3 +1,10 @@
# Baritone
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

View File

@ -16,7 +16,7 @@
*/
group 'baritone'
version '1.0'
version '1.0.0'
buildscript {
repositories {
@ -75,3 +75,8 @@ dependencies {
}
testImplementation 'junit:junit:4.12'
}
mixin {
defaultObfuscationEnv notch
add sourceSets.main, 'mixins.baritone.refmap.json'
}

View File

@ -21,6 +21,7 @@ import baritone.behavior.Behavior;
import baritone.behavior.impl.LookBehavior;
import baritone.behavior.impl.MemoryBehavior;
import baritone.behavior.impl.PathingBehavior;
import baritone.behavior.impl.LocationTrackingBehavior;
import baritone.event.GameEventHandler;
import baritone.map.Map;
import baritone.utils.InputOverrideHandler;
@ -72,6 +73,7 @@ public enum Baritone {
registerBehavior(LookBehavior.INSTANCE);
registerBehavior(MemoryBehavior.INSTANCE);
registerBehavior(Map.INSTANCE);
registerBehavior(LocationTrackingBehavior.INSTANCE);
}
this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");

View File

@ -107,12 +107,25 @@ public class Settings {
*/
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
* entirely within currently loaded chunks. Improves path safety because cached chunks are heavily simplified.
*/
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
*/
@ -141,6 +154,13 @@ public class Settings {
*/
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
* 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);
/**
* 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
*/
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 List<Setting<?>> allSettings;
@ -291,7 +324,7 @@ public class Settings {
@SuppressWarnings("unchecked")
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) {
if (setting.klass.equals(klass)) {
result.add((Setting<T>) setting);

View File

@ -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()));
}
}

View File

@ -58,21 +58,42 @@ public class LookBehavior extends Behavior {
@Override
public void onPlayerUpdate(PlayerUpdateEvent event) {
if (event.getState() == EventState.PRE && this.target != null && this.force) {
player().rotationYaw = this.target.getFirst();
float oldPitch = player().rotationPitch;
float desiredPitch = this.target.getSecond();
player().rotationPitch = desiredPitch;
if (desiredPitch == oldPitch) {
nudgeToLevel();
if (this.target == null)
return;
// Whether or not we're going to silently set our angles
boolean silent = Baritone.settings().antiCheatCompatibility.get();
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
public void onPlayerRelativeMove(RelativeMoveEvent event) {
if (this.target != null && !force) {
if (this.target != null && !this.force) {
switch (event.getState()) {
case PRE:
this.lastYaw = player().rotationYaw;
@ -80,7 +101,10 @@ public class LookBehavior extends Behavior {
break;
case POST:
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;
}
}

View File

@ -19,6 +19,7 @@ package baritone.behavior.impl;
import baritone.Baritone;
import baritone.behavior.Behavior;
import baritone.event.events.PathEvent;
import baritone.event.events.PlayerUpdateEvent;
import baritone.event.events.RenderEvent;
import baritone.event.events.TickEvent;
@ -59,6 +60,10 @@ public class PathingBehavior extends Behavior {
private boolean lastAutoJump;
private void dispatchPathEvent(PathEvent event) {
new Thread(() -> Baritone.INSTANCE.getGameEventHandler().onPathEvent(event)).start();
}
@Override
public void onTick(TickEvent event) {
if (event.getType() == TickEvent.Type.OUT) {
@ -74,6 +79,7 @@ public class PathingBehavior extends Behavior {
current = null;
if (goal == null || goal.isInGoal(playerFeet())) {
displayChatMessageRaw("All done. At " + goal);
dispatchPathEvent(PathEvent.AT_GOAL);
next = null;
return;
}
@ -85,10 +91,12 @@ public class PathingBehavior extends Behavior {
// but if we fail in the middle of current
// we're nowhere close to our planned ahead path
// so need to discard it sadly.
dispatchPathEvent(PathEvent.DISCARD_NEXT);
next = null;
}
if (next != null) {
displayChatMessageRaw("Continuing on to planned next path");
dispatchPathEvent(PathEvent.CONTINUING_ONTO_PLANNED_NEXT);
current = next;
next = null;
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
synchronized (pathCalcLock) {
if (isPathCalcInProgress) {
dispatchPathEvent(PathEvent.PATH_FINISHED_NEXT_STILL_CALCULATING);
// if we aren't calculating right now
return;
}
dispatchPathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true, Optional.empty());
}
return;
@ -110,6 +120,7 @@ public class PathingBehavior extends Behavior {
if (next.getPath().positions().contains(playerFeet())) {
// jump directly onto the next path
displayChatMessageRaw("Splicing into planned next path early...");
dispatchPathEvent(PathEvent.SPLICING_ONTO_NEXT_EARLY);
current = next;
next = null;
return;
@ -132,6 +143,7 @@ public class PathingBehavior extends Behavior {
if (ticksRemainingInSegment().get() < Baritone.settings().planningTickLookAhead.get()) {
// and this path has 5 seconds or less left
displayChatMessageRaw("Path almost over. Planning ahead...");
dispatchPathEvent(PathEvent.NEXT_SEGMENT_CALC_STARTED);
findPathInNewThread(current.getPath().getDest(), false, Optional.of(current.getPath()));
}
}
@ -164,6 +176,10 @@ public class PathingBehavior extends Behavior {
this.goal = goal;
}
public Goal getGoal() {
return goal;
}
public PathExecutor getCurrent() {
return current;
}
@ -192,6 +208,7 @@ public class PathingBehavior extends Behavior {
if (isPathCalcInProgress) {
return;
}
dispatchPathEvent(PathEvent.CALC_STARTED);
findPathInNewThread(pathStart(), true, Optional.empty());
}
}
@ -227,19 +244,29 @@ public class PathingBehavior extends Behavior {
if (Baritone.settings().cutoffAtLoadBoundary.get()) {
path = path.map(IPath::cutoffAtLoadedChunks);
}
path.map(p -> p.staticCutoff(goal)).map(PathExecutor::new).ifPresent(p -> {
synchronized (pathPlanLock) {
if (current == null) {
current = p;
Optional<PathExecutor> executor = path.map(p -> p.staticCutoff(goal)).map(PathExecutor::new);
synchronized (pathPlanLock) {
if (current == null) {
if (executor.isPresent()) {
dispatchPathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING);
current = executor.get();
} else {
if (next == null) {
next = p;
dispatchPathEvent(PathEvent.CALC_FAILED);
}
} else {
if (next == null) {
if (executor.isPresent()) {
dispatchPathEvent(PathEvent.NEXT_SEGMENT_CALC_FINISHED);
next = executor.get();
} 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 (goal == null || goal.isInGoal(current.getPath().getDest())) {
displayChatMessageRaw("Finished finding a path from " + start + " to " + goal + ". " + current.getPath().getNumNodesConsidered() + " nodes considered");

View File

@ -21,8 +21,10 @@ import baritone.utils.pathing.IBlockTypeAccess;
import baritone.utils.pathing.PathingBlockType;
import net.minecraft.block.Block;
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
@ -30,6 +32,39 @@ import java.util.BitSet;
*/
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.
* <p>
@ -66,7 +101,9 @@ public final class CachedChunk implements IBlockTypeAccess {
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);
this.x = x;
@ -74,6 +111,7 @@ public final class CachedChunk implements IBlockTypeAccess {
this.data = data;
this.overview = overview;
this.heightMap = new int[256];
this.specialBlockLocations = specialBlockLocations;
calculateHeightMap();
}
@ -82,11 +120,7 @@ public final class CachedChunk implements IBlockTypeAccess {
int internalPos = z << 4 | x;
if (heightMap[internalPos] == y) {
// we have this exact block, it's a surface block
String name = overview[internalPos];
if (!name.contains(":")) {
name = "minecraft:" + name;
}
IBlockState state = Block.getBlockFromName(name).getDefaultState();
IBlockState state = ChunkPacker.stringToBlock(overview[internalPos]).getDefaultState();
//System.out.println("Saying that " + x + "," + y + "," + z + " is " + state);
return state;
}
@ -118,6 +152,21 @@ public final class CachedChunk implements IBlockTypeAccess {
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
*/

View File

@ -19,13 +19,13 @@ package baritone.chunk;
import baritone.utils.pathing.IBlockTypeAccess;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.BitSet;
import java.util.function.Consumer;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
@ -70,34 +70,39 @@ public final class CachedRegion implements IBlockTypeAccess {
@Override
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) {
return chunk.getBlock(x & 15, y, z & 15);
}
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;
hasUnsavedChanges = true;
}
private CachedChunk getChunk(int chunkX, int chunkZ) {
return this.chunks[chunkX][chunkZ];
}
public void forEachChunk(Consumer<CachedChunk> consumer) {
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) {
public synchronized final void save(String directory) {
if (!hasUnsavedChanges) {
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;
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 {
Path path = Paths.get(directory);
if (!Files.exists(path))
@ -174,6 +194,7 @@ public final class CachedRegion implements IBlockTypeAccess {
throw new IOException("Bad magic value " + magic);
}
CachedChunk[][] tmpCached = new CachedChunk[32][32];
Map<String, List<BlockPos>>[][] location = new Map[32][32];
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
int isChunkPresent = in.read();
@ -181,7 +202,12 @@ public final class CachedRegion implements IBlockTypeAccess {
case CHUNK_PRESENT:
byte[] bytes = new byte[CachedChunk.SIZE_IN_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;
case CHUNK_NOT_PRESENT:
tmpCached[x][z] = null;
@ -200,9 +226,33 @@ public final class CachedRegion implements IBlockTypeAccess {
}
}
}
int fileEndMagic = in.readInt();
if (fileEndMagic != ~magic) {
throw new IOException("Bad end of file magic");
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
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
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
*/

View File

@ -17,16 +17,18 @@
package baritone.chunk;
import baritone.Baritone;
import baritone.utils.pathing.IBlockTypeAccess;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.BitSet;
import java.util.LinkedList;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.function.Consumer;
@ -64,6 +66,21 @@ public final class CachedWorld implements IBlockTypeAccess {
// Insert an invalid region element
cachedRegions.put(0, null);
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) {
@ -84,12 +101,45 @@ public final class CachedWorld implements IBlockTypeAccess {
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) {
CachedRegion region = getOrCreateRegion(chunk.x >> 5, chunk.z >> 5);
region.updateCachedChunk(chunk.x & 31, chunk.z & 31, chunk);
}
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();
this.cachedRegions.values().forEach(region -> {
if (region != null)
@ -99,6 +149,16 @@ public final class CachedWorld implements IBlockTypeAccess {
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
*
@ -118,7 +178,7 @@ public final class CachedWorld implements IBlockTypeAccess {
* @param regionZ The region Z coordinate
* @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 -> {
CachedRegion newRegion = new CachedRegion(regionX, regionZ);
newRegion.load(this.directory);
@ -168,9 +228,7 @@ public final class CachedWorld implements IBlockTypeAccess {
}
try {
Chunk chunk = queue.take();
BitSet packedChunk = ChunkPacker.createPackedChunk(chunk);
String[] packedOverview = ChunkPacker.createPackedOverview(chunk);
CachedChunk cached = new CachedChunk(chunk.x, chunk.z, packedChunk, packedOverview);
CachedChunk cached = ChunkPacker.pack(chunk);
CachedWorld.this.updateCachedChunk(cached);
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
} catch (InterruptedException e) {

View File

@ -28,9 +28,10 @@ import net.minecraft.block.BlockTallGrass;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.Chunk;
import java.util.BitSet;
import java.util.*;
/**
* @author Brady
@ -40,30 +41,33 @@ public final class ChunkPacker implements Helper {
private ChunkPacker() {}
public static BitSet createPackedChunk(Chunk chunk) {
public static CachedChunk pack(Chunk chunk) {
long start = System.currentTimeMillis();
Map<String, List<BlockPos>> specialBlocks = new HashMap<>();
BitSet bitSet = new BitSet(CachedChunk.SIZE);
try {
for (int y = 0; y < 256; y++) {
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
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 + 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) {
e.printStackTrace();
}
//System.out.println("Packed special blocks: " + specialBlocks);
long end = System.currentTimeMillis();
//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];
for (int z = 0; z < 16; z++) {
for (int x = 0; x < 16; x++) {
@ -75,17 +79,29 @@ public final class ChunkPacker implements Helper {
break;
}
}
ResourceLocation loc = Block.REGISTRY.getNameForObject(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
}
String name = blockToString(blockState.getBlock());
blockNames[z << 4 | x] = name;
}
}
long end = System.currentTimeMillis();
return blockNames;
CachedChunk cached = new CachedChunk(chunk.x, chunk.z, bitSet, blockNames, specialBlocks);
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) {
@ -96,7 +112,6 @@ public final class ChunkPacker implements Helper {
if (MovementHelper.avoidWalkingInto(block)) {
return PathingBlockType.AVOID;
}
// We used to do an AABB check here
// 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
@ -118,7 +133,18 @@ public final class ChunkPacker implements Helper {
case AVOID:
return Blocks.LAVA.getDefaultState();
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;

View File

@ -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);
}
}

View File

@ -17,12 +17,27 @@
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.Path;
import java.util.*;
/**
* Waypoints for a world
*
* @author leijurv
*/
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 Map<Waypoint.Tag, Set<Waypoint>> waypoints;
Waypoints(Path directory) {
this.directory = directory;
@ -32,5 +47,78 @@ public class Waypoints {
} catch (IOException ignored) {}
}
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);
}
}

View File

@ -19,6 +19,11 @@ package baritone.chunk;
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 final CachedWorld cache;
public final Waypoints waypoints;

View File

@ -26,6 +26,7 @@ import net.minecraft.server.integrated.IntegratedServer;
import net.minecraft.world.WorldServer;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -52,6 +53,7 @@ public enum WorldProvider implements Helper {
public final void initWorld(WorldClient world) {
int dimensionID = world.provider.getDimensionType().getId();
File directory;
File readme;
IntegratedServer integratedServer = mc.getIntegratedServer();
if (integratedServer != null) {
WorldServer localServerWorld = integratedServer.getWorld(dimensionID);
@ -59,17 +61,26 @@ public enum WorldProvider implements Helper {
IAnvilChunkLoader loader = (IAnvilChunkLoader) provider.getChunkLoader();
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
directory = directory.getParentFile();
}
directory = new File(directory, "baritone");
readme = directory;
} else {
//remote
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);
Path dir = directory.toPath();
if (!Files.exists(dir)) {

View File

@ -42,10 +42,6 @@ import baritone.event.listener.IGameEventListener;
import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler;
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.world.chunk.Chunk;
import org.lwjgl.input.Keyboard;
@ -111,15 +107,14 @@ public final class GameEventHandler implements IGameEventListener, Helper {
&& type == ChunkEvent.Type.UNLOAD
&& mc.world.getChunkProvider().isChunkGeneratedAt(event.getX(), event.getZ());
if (Baritone.settings().chunkCaching.get()) {
if (isPostPopulate || isPreUnload) {
WorldProvider.INSTANCE.ifWorldLoaded(world -> {
Chunk chunk = mc.world.getChunk(event.getX(), event.getZ());
world.cache.queueForPacking(chunk);
});
}
if (isPostPopulate || isPreUnload) {
WorldProvider.INSTANCE.ifWorldLoaded(world -> {
Chunk chunk = mc.world.getChunk(event.getX(), event.getZ());
world.cache.queueForPacking(chunk);
});
}
dispatch(listener -> listener.onChunkEvent(event));
}
@ -136,19 +131,17 @@ public final class GameEventHandler implements IGameEventListener, Helper {
@Override
public final void onWorldEvent(WorldEvent event) {
if (Baritone.settings().chunkCaching.get()) {
WorldProvider cache = WorldProvider.INSTANCE;
WorldProvider cache = WorldProvider.INSTANCE;
switch (event.getState()) {
case PRE:
cache.closeWorld();
break;
case POST:
cache.closeWorld();
if (event.getWorld() != null)
cache.initWorld(event.getWorld());
break;
}
switch (event.getState()) {
case PRE:
cache.closeWorld();
break;
case POST:
cache.closeWorld();
if (event.getWorld() != null)
cache.initWorld(event.getWorld());
break;
}
dispatch(listener -> listener.onWorldEvent(event));
@ -174,6 +167,21 @@ public final class GameEventHandler implements IGameEventListener, Helper {
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) {
this.listeners.add(listener);
}
@ -185,27 +193,4 @@ public final class GameEventHandler implements IGameEventListener, Helper {
private boolean canDispatch(IGameEventListener listener) {
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();
}
}

View File

@ -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
}
}

View File

@ -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
}

View File

@ -41,9 +41,8 @@ import baritone.event.events.*;
* overridden with empty bodies, allowing inheritors of this class to choose
* which events they would like to listen in on.
*
* @see IGameEventListener
*
* @author Brady
* @see IGameEventListener
* @since 8/1/2018 6:29 PM
*/
public interface AbstractGameEventListener extends IGameEventListener {
@ -80,4 +79,13 @@ public interface AbstractGameEventListener extends IGameEventListener {
@Override
default void onPlayerRelativeMove(RelativeMoveEvent event) {}
@Override
default void onBlockInteract(BlockInteractEvent event) {}
@Override
default void onPlayerDeath() {}
@Override
default void onPathEvent(PathEvent event) {}
}

View File

@ -39,6 +39,7 @@ import io.netty.util.concurrent.GenericFutureListener;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiGameOver;
import net.minecraft.client.multiplayer.WorldClient;
import net.minecraft.client.renderer.EntityRenderer;
import net.minecraft.client.settings.GameSettings;
@ -46,6 +47,7 @@ import net.minecraft.entity.Entity;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
import net.minecraft.util.text.ITextComponent;
/**
* @author Brady
@ -132,4 +134,26 @@ public interface IGameEventListener {
* @see Entity#moveRelative(float, float, float, float)
*/
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);
}

View File

@ -1,40 +1,43 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU 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.launch.mixins;
import net.minecraft.client.main.Main;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
/**
* @author Brady
* @since 7/31/2018 10:18 PM
*/
@Mixin(Main.class)
public class MixinMain {
@Inject(
method = "main",
at = @At("HEAD")
)
private static void main(String[] args, CallbackInfo ci) {
System.setProperty("java.net.preferIPv4Stack", "true");
}
}
/*
* 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.launch.mixins;
import com.google.common.base.MoreObjects;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3i;
import org.spongepowered.asm.mixin.Mixin;
import javax.annotation.Nonnull;
/**
* @author Brady
* @since 8/25/2018
*/
@Mixin(BlockPos.class)
public abstract class MixinBlockPos extends Vec3i {
public MixinBlockPos(int xIn, int yIn, int zIn) {
super(xIn, yIn, zIn);
}
@Override
@Nonnull
public String toString() {
return MoreObjects.toStringHelper("BlockPos").add("x", this.getX()).add("y", this.getY()).add("z", this.getZ()).toString();
}
}

View File

@ -34,7 +34,8 @@ public class MixinGameSettings {
method = "isKeyDown",
at = @At(
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) {

View File

@ -37,7 +37,8 @@ public class MixinGuiContainer {
},
at = @At(
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) {

View File

@ -38,7 +38,8 @@ public class MixinGuiScreen {
},
at = @At(
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) {

View File

@ -19,13 +19,19 @@ package baritone.launch.mixins;
import baritone.Baritone;
import baritone.behavior.impl.PathingBehavior;
import baritone.event.events.BlockInteractEvent;
import baritone.event.events.TickEvent;
import baritone.event.events.WorldEvent;
import baritone.event.events.type.EventState;
import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
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.mixin.Mixin;
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.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
/**
* @author Brady
@ -42,6 +49,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
public class MixinMinecraft {
@Shadow private int leftClickCounter;
@Shadow public EntityPlayerSP player;
@Shadow public WorldClient world;
@Inject(
@ -78,7 +86,8 @@ public class MixinMinecraft {
method = "runTickKeyboard",
at = @At(
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) {
@ -93,23 +102,6 @@ public class MixinMinecraft {
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(
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
at = @At("HEAD")
@ -153,6 +145,30 @@ public class MixinMinecraft {
)
)
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));
}
}

View File

@ -22,6 +22,7 @@ import baritone.event.events.ChunkEvent;
import baritone.event.events.type.EventState;
import net.minecraft.client.network.NetHandlerPlayClient;
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.injection.At;
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();
}
}

View File

@ -64,8 +64,7 @@ public abstract class MixinNetworkManager {
at = @At(
value = "INVOKE",
target = "net/minecraft/network/Packet.processPacket(Lnet/minecraft/network/INetHandler;)V"
),
remap = false
)
)
private void preProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent(EventState.PRE, packet));
@ -73,8 +72,7 @@ public abstract class MixinNetworkManager {
@Inject(
method = "channelRead0",
at = @At("RETURN"),
remap = false
at = @At("RETURN")
)
private void postProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
if (this.channel.isOpen())

View File

@ -77,8 +77,7 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
int numNodes = 0;
int numEmptyChunk = 0;
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();
int pathingMaxChunkBorderFetch = Baritone.settings().pathingMaxChunkBorderFetch.get(); // grab all settings beforehand so that changing settings during pathing doesn't cause a crash or unpredictable behavior
double favorCoeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
boolean minimumImprovementRepropagation = Baritone.settings().minimumImprovementRepropagation.get();
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && System.currentTimeMillis() < timeoutTime) {
@ -112,11 +111,9 @@ public class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
}
BetterBlockPos dest = (BetterBlockPos) movementToGetToNeighbor.getDest();
boolean isPositionCached = false;
if (cache) {
if (WorldProvider.INSTANCE.getCurrentWorld() != null) {
if (WorldProvider.INSTANCE.getCurrentWorld().cache.getBlock(dest) != null) {
isPositionCached = true;
}
if (WorldProvider.INSTANCE.getCurrentWorld() != null) {
if (WorldProvider.INSTANCE.getCurrentWorld().cache.getBlock(dest) != null) {
isPositionCached = true;
}
}
if (!isPositionCached && Minecraft.getMinecraft().world.getChunk(dest) instanceof EmptyChunk) {

View File

@ -64,6 +64,9 @@ public class GoalXZ implements Goal {
}
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
//It takes into account the fact that pathing can either walk diagonally or forwards

View File

@ -48,7 +48,7 @@ public class GoalYLevel implements Goal {
}
if (pos.getY() < level) {
// need to ascend
return (level - pos.getY()) * JUMP_ONE_BLOCK_COST * 0.9;
return (level - pos.getY()) * JUMP_ONE_BLOCK_COST;
}
return 0;
}

View File

@ -29,9 +29,12 @@ import net.minecraft.block.Block;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import static baritone.utils.InputOverrideHandler.Input;
@ -54,6 +57,8 @@ public abstract class Movement implements Helper, MovementHelper {
*/
protected final BlockPos[] positionsToPlace;
private boolean didBreakLastTick;
private Double cost;
protected Movement(BlockPos src, BlockPos dest, BlockPos[] toBreak, BlockPos[] toPlace) {
@ -100,7 +105,6 @@ public abstract class Movement implements Helper, MovementHelper {
* @return Status
*/
public MovementStatus update() {
player().setSprinting(false);
MovementState latestState = updateState(currentState);
if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true);
@ -114,10 +118,29 @@ public abstract class Movement implements Helper, MovementHelper {
// 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
this.didBreakLastTick = false;
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);
});
latestState.getInputStates().replaceAll((input, forced) -> false);
if (!this.didBreakLastTick)
BlockBreakHelper.stopBreakingBlock();
currentState = latestState;
if (isFinished())
@ -187,41 +210,58 @@ public abstract class Movement implements Helper, MovementHelper {
currentState.setStatus(MovementStatus.CANCELED);
}
public void reset() {
currentState = new MovementState().setStatus(MovementStatus.PREPPING);
}
public double getTotalHardnessOfBlocksToBreak(CalculationContext ctx) {
/*
double sum = 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();
}
if (positionsToBreak.length == 0) {
return 0;
}
for (BlockPos pos : toBreak) {
sum += getHardness(ts, Baritone.get(pos), pos);
if (sum >= COST_INF) {
return COST_INF;
}
if (positionsToBreak.length == 1) {
return MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[0], true);
}
if (!Baritone.allowBreakOrPlace || !Baritone.hasThrowaway) {
for (int i = 0; i < blocksToPlace.length; i++) {
if (!canWalkOn(positionsToPlace[i])) {
return COST_INF;
int firstColumnX = positionsToBreak[0].getX();
int firstColumnZ = positionsToBreak[0].getZ();
int firstColumnMaxY = positionsToBreak[0].getY();
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;
for (BlockPos pos : positionsToBreak) {
sum += MovementHelper.getMiningDurationTicks(ctx, pos);
for (int i = 0; i < positionsToBreak.length; i++) {
sum += MovementHelper.getMiningDurationTicks(ctx, positionsToBreak[i], firstColumnMaximalIndex == i || secondColumnMaximalIndex == i);
if (sum >= COST_INF) {
return COST_INF;
break;
}
}
return sum;
@ -243,15 +283,19 @@ public abstract class Movement implements Helper, MovementHelper {
return state;
}
public ArrayList<BlockPos> toBreakCached = null;
public ArrayList<BlockPos> toPlaceCached = null;
public ArrayList<BlockPos> toWalkIntoCached = null;
public BlockPos getDirection() {
return getDest().subtract(getSrc());
}
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) {
return toBreakCached;
}
ArrayList<BlockPos> result = new ArrayList<>();
List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToBreak) {
if (!MovementHelper.canWalkThrough(positionToBreak)) {
result.add(positionToBreak);
@ -261,11 +305,11 @@ public abstract class Movement implements Helper, MovementHelper {
return result;
}
public ArrayList<BlockPos> toPlace() {
public List<BlockPos> toPlace() {
if (toPlaceCached != null) {
return toPlaceCached;
}
ArrayList<BlockPos> result = new ArrayList<>();
List<BlockPos> result = new ArrayList<>();
for (BlockPos positionToBreak : positionsToPlace) {
if (!MovementHelper.canWalkOn(positionToBreak)) {
result.add(positionToBreak);
@ -275,7 +319,7 @@ public abstract class Movement implements Helper, MovementHelper {
return result;
}
public ArrayList<BlockPos> toWalkInto() { // overridden by movementdiagonal
public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>();
}

View File

@ -24,15 +24,18 @@ import baritone.pathing.movement.movements.MovementDescend;
import baritone.pathing.movement.movements.MovementFall;
import baritone.utils.*;
import net.minecraft.block.*;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.chunk.EmptyChunk;
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
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());
if (BlockStateInterface.isFlowing(state) || up.getBlock() instanceof BlockLiquid || up.getBlock() instanceof BlockLilyPad) {
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);
}
static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
IBlockState door = BlockStateInterface.get(doorPos);
if (!(door.getBlock() instanceof BlockDoor)) {
return true;
}
String facing = door.getValue(BlockDoor.FACING).getName();
boolean open = door.getValue(BlockDoor.OPEN).booleanValue();
/**
* yes this is dumb
* change it if you want
static boolean isReplacable(BlockPos pos, IBlockState state) {
// for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case
// all other overrides just return true or false
// the only case to deal with is snow
/*
* public boolean isReplaceable(IBlockAccess worldIn, BlockPos pos)
* {
* return ((Integer)worldIn.getBlockState(pos).getValue(LAYERS)).intValue() == 1;
* }
*/
String playerFacing = "";
if (playerPos.equals(doorPos)) {
return false;
if (state.getBlock() instanceof BlockSnow) {
// as before, 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;
}
}
if (playerPos.north().equals(doorPos) || playerPos.south().equals(doorPos)) {
playerFacing = "northsouth";
} else if (playerPos.east().equals(doorPos) || playerPos.west().equals(doorPos)) {
playerFacing = "eastwest";
return state.getBlock().isReplaceable(mc.world, pos);
}
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 {
return true;
}
if (facing == "north" || facing == "south") {
if (open) {
return playerFacing == "northsouth";
} else {
return playerFacing == "eastwest";
}
} else {
if (open) {
return playerFacing == "eastwest";
} else {
return playerFacing == "northsouth";
}
}
return facing == playerFacing == open;
}
static boolean avoidWalkingInto(Block block) {
@ -170,12 +208,12 @@ public interface MovementHelper extends ActionCosts, Helper {
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);
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();
if (!block.equals(Blocks.AIR) && !canWalkThrough(position, state)) { // TODO is the air check really necessary? Isn't air canWalkThrough?
if (!context.allowBreak()) {
@ -185,9 +223,17 @@ public interface MovementHelper extends ActionCosts, Helper {
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
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) {
// A
//SA
// B
// A
// B
// C
// 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
//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
return new MovementDescend(pos, dest.down()); // standard move out by 1 and descend by 1
}
if (!canWalkThrough(dest.down(2))) {
//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
// let's see how far we can fall
for (int fallHeight = 3; true; fallHeight++) {

View File

@ -64,15 +64,20 @@ public class MovementAscend extends Movement {
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend
}
@Override
public void reset() {
super.reset();
ticksWithoutPlacement = 0;
}
@Override
protected double calculateCost(CalculationContext context) {
IBlockState toPlace = BlockStateInterface.get(positionsToPlace[0]);
if (!MovementHelper.canWalkOn(positionsToPlace[0], toPlace)) {
if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock())) {
// TODO replace this check with isReplacable or similar
if (!context.hasThrowaway()) {
return COST_INF;
}
if (!context.hasThrowaway()) {
if (!BlockStateInterface.isAir(toPlace) && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(positionsToPlace[0], toPlace)) {
return COST_INF;
}
for (BlockPos against1 : against) {
@ -125,9 +130,9 @@ public class MovementAscend extends Movement {
default:
return state;
}
if (playerFeet().equals(dest)) {
state.setStatus(MovementStatus.SUCCESS);
return state;
return state.setStatus(MovementStatus.SUCCESS);
}
if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
@ -141,34 +146,56 @@ public class MovementAscend extends Movement {
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));
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), anAgainst) && LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionsToPlace[0])) {
ticksWithoutPlacement++;
state.setInput(InputOverrideHandler.Input.SNEAK, true);
if (player().isSneaking()) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionsToPlace[0])) {
ticksWithoutPlacement++;
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) {
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());
System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
});
return state;
}
}
return state.setStatus(MovementStatus.UNREACHABLE);
}
MovementHelper.moveTowards(state, dest);
state.setInput(InputOverrideHandler.Input.JUMP, true);
// TODO check if the below actually helps or hurts, it's weird
//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);
//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);
if (headBonkClear()) {
return state.setInput(InputOverrideHandler.Input.JUMP, true);
}
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;
}
}

View File

@ -36,6 +36,12 @@ public class MovementDescend extends Movement {
super(start, end, new BlockPos[]{end.up(2), end.up(), end}, new BlockPos[]{end.down()});
}
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override
protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(positionsToPlace[0])) {
@ -67,6 +73,7 @@ public class MovementDescend extends Movement {
default:
return state;
}
BlockPos playerFeet = playerFeet();
if (playerFeet.equals(dest)) {
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);
if (!playerFeet.equals(dest) || ab > 0.25) {
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) {
MovementHelper.moveTowards(state, fakeDest);
if (fromStart > 1.25) {

View File

@ -22,6 +22,7 @@ import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.BlockMagma;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@ -29,6 +30,7 @@ import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import java.util.ArrayList;
import java.util.List;
public class MovementDiagonal extends Movement {
@ -58,12 +60,13 @@ public class MovementDiagonal extends Movement {
default:
return state;
}
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
}
if (!BlockStateInterface.isLiquid(playerFeet())) {
player().setSprinting(true);
state.setInput(InputOverrideHandler.Input.SPRINT, true);
}
MovementHelper.moveTowards(state, dest);
return state;
@ -80,7 +83,7 @@ public class MovementDiagonal extends Movement {
}
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)) {
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) {
return COST_INF;
}
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3]);
double optionA = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0], false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1], true);
double optionB = MovementHelper.getMiningDurationTicks(context, positionsToBreak[2], false) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[3], true);
if (optionA != 0 && optionB != 0) {
return COST_INF;
}
@ -116,17 +119,17 @@ public class MovementDiagonal extends Movement {
}
}
if (BlockStateInterface.isWater(src) || BlockStateInterface.isWater(dest)) {
// ignore previous multiplier
// whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// not even touching the blocks below
// Ignore previous multiplier
// Whatever we were walking on (possibly soul sand) doesn't matter as we're actually floating on water
// Not even touching the blocks below
multiplier = WALK_ONE_IN_WATER_COST;
}
if (optionA != 0 || optionB != 0) {
multiplier *= SQRT_2 - 0.001; // TODO tune
}
if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) {
// if we aren't edging around anything, and we aren't in water or soul sand
// we can sprint =D
// If we aren't edging around anything, and we aren't in water or soul sand
// We can sprint =D
multiplier = SPRINT_ONE_BLOCK_COST;
}
return multiplier * SQRT_2;
@ -138,11 +141,11 @@ public class MovementDiagonal extends Movement {
}
@Override
public ArrayList<BlockPos> toBreak() {
public List<BlockPos> toBreak() {
if (toBreakCached != null) {
return toBreakCached;
}
ArrayList<BlockPos> result = new ArrayList<>();
List<BlockPos> result = new ArrayList<>();
for (int i = 4; i < 6; i++) {
if (!MovementHelper.canWalkThrough(positionsToBreak[i])) {
result.add(positionsToBreak[i]);
@ -153,11 +156,11 @@ public class MovementDiagonal extends Movement {
}
@Override
public ArrayList<BlockPos> toWalkInto() {
public List<BlockPos> toWalkInto() {
if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>();
}
ArrayList<BlockPos> result = new ArrayList<>();
List<BlockPos> result = new ArrayList<>();
for (int i = 0; i < 4; i++) {
if (!MovementHelper.canWalkThrough(positionsToBreak[i])) {
result.add(positionsToBreak[i]);

View File

@ -36,6 +36,12 @@ public class MovementDownward extends Movement {
super(start, end, new BlockPos[]{end}, new BlockPos[0]);
}
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override
protected double calculateCost(CalculationContext context) {
if (!MovementHelper.canWalkOn(dest.down())) {
@ -47,7 +53,8 @@ public class MovementDownward extends Movement {
if (ladder) {
return LADDER_DOWN_ONE_COST;
} 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:
return state;
}
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;

View File

@ -18,25 +18,20 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.behavior.impl.LookBehaviorUtils;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.Rotation;
import baritone.utils.Utils;
import net.minecraft.block.Block;
import baritone.utils.*;
import net.minecraft.block.BlockFalling;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import java.util.Optional;
public class MovementFall extends Movement {
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
@ -61,22 +56,29 @@ public class MovementFall extends Movement {
}
placeBucketCost = context.placeBlockCost();
}
double frontTwo = MovementHelper.getMiningDurationTicks(context, positionsToBreak[0]) + MovementHelper.getMiningDurationTicks(context, positionsToBreak[1]);
if (frontTwo >= COST_INF) {
double frontThree = 0;
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;
}
for (int i = 2; i < positionsToBreak.length; i++) {
for (int i = 3; i < positionsToBreak.length; i++) {
// TODO is this the right check here?
// 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
// 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?
if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i]) > 0) {
// 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
// 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?
if (MovementHelper.getMiningDurationTicks(context, positionsToBreak[i], false) > 0) {
//can't break while falling
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
@ -90,21 +92,28 @@ public class MovementFall extends Movement {
default:
return state;
}
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 (!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);
return state;
}
if (player().posY - dest.getY() < mc.playerController.getBlockReachDistance()) {
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()) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true)
.setTarget(new MovementTarget(targetRotation.get(), true));
if (targetRotation != null) {
state.setTarget(new MovementTarget(targetRotation, true));
} else {
state.setTarget(new MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.getBlockPosCenter(dest)), false));
}

View File

@ -38,6 +38,12 @@ public class MovementPillar extends Movement {
super(start, end, new BlockPos[]{start.up(2)}, new BlockPos[]{start});
}
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override
protected double calculateCost(CalculationContext context) {
Block fromDown = BlockStateInterface.get(src).getBlock();
@ -109,6 +115,7 @@ public class MovementPillar extends Movement {
default:
return state;
}
IBlockState fromDown = BlockStateInterface.get(src);
boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine;
boolean vine = fromDown.getBlock() instanceof BlockVine;
@ -117,57 +124,68 @@ public class MovementPillar extends Movement {
Utils.getBlockPosCenter(positionsToPlace[0]),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)), true));
}
EntityPlayerSP thePlayer = Minecraft.getMinecraft().player;
boolean blockIsThere = MovementHelper.canWalkOn(src) || ladder;
if (ladder) {
BlockPos against = vine ? getAgainst(src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite());
if (against == null) {
displayChatMessageRaw("Unable to climb vines");
state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state;
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
}
if (playerFeet().equals(against.up()) || playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
if (playerFeet().equals(against.up()) || playerFeet().equals(dest))
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);
return state;
} 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);
return state;
}
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);
//otherwise jump
// Otherwise jump
if (numTicks > 40) {
double diffX = thePlayer.posX - (dest.getX() + 0.5);
double diffZ = thePlayer.posZ - (dest.getZ() + 0.5);
double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = player().posZ - (dest.getZ() + 0.5);
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
//[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
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) {
Block fr = BlockStateInterface.get(src).getBlock();
if (!(fr instanceof BlockAir || fr.isReplaceable(Minecraft.getMinecraft().world, src))) {
state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
blockIsThere = false;
} 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);
return state;//we are done
// If we are at our goal and the block below us is placed
if (playerFeet().equals(dest) && blockIsThere) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
}
return state;
}
}

View File

@ -25,10 +25,7 @@ import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils;
import net.minecraft.block.Block;
import net.minecraft.block.BlockDoor;
import net.minecraft.block.BlockLadder;
import net.minecraft.block.BlockVine;
import net.minecraft.block.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
@ -66,6 +63,12 @@ public class MovementTraverse extends Movement {
//note: do NOT add ability to place against .down().down()
}
@Override
public void reset() {
super.reset();
wasTheBridgeBlockAlwaysThere = true;
}
@Override
protected double calculateCost(CalculationContext context) {
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 (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
// we can sprint =D
// 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
WC = SPRINT_ONE_BLOCK_COST;
}
return WC;
}
//double hardness1 = blocksToBreak[0].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[0]);
//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 + ")");
// double hardness1 = blocksToBreak[0].getBlockHardness(Minecraft.getMinecraft().world, positionsToBreak[0]);
// 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 + ")");
return WC + getTotalHardnessOfBlocksToBreak(context);
} else {//this is a bridge, so we need to place a block
Block srcDown = BlockStateInterface.get(src.down()).getBlock();
@ -101,7 +104,7 @@ public class MovementTraverse extends Movement {
return COST_INF;
}
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()) {
return COST_INF;
}
@ -118,7 +121,7 @@ public class MovementTraverse extends Movement {
return WC + context.placeBlockCost() + getTotalHardnessOfBlocksToBreak(context);
}
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:
return state;
}
Block fd = BlockStateInterface.get(src.down()).getBlock();
boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine;
IBlockState pb0 = BlockStateInterface.get(positionsToBreak[0]);
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) {
boolean isDoorActuallyBlockingUs = false;
Block srcBlock = BlockStateInterface.get(src).getBlock();
if (srcBlock instanceof BlockDoor && !MovementHelper.isDoorPassable(src, dest)) {
if (pb0.getBlock() instanceof BlockDoor && !MovementHelper.isDoorPassable(src, dest)) {
isDoorActuallyBlockingUs = true;
} else if (pb1.getBlock() instanceof BlockDoor && !MovementHelper.isDoorPassable(dest, src)) {
isDoorActuallyBlockingUs = true;
}
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.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
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;
BlockPos whereAmI = playerFeet();
if (whereAmI.getY() != dest.getY() && !ladder) {
@ -163,13 +183,14 @@ public class MovementTraverse extends Movement {
}
return state;
}
if (isTheBridgeBlockThere) {
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
return state;
}
if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) {
player().setSprinting(true);
state.setInput(InputOverrideHandler.Input.SPRINT, true);
}
Block destDown = BlockStateInterface.get(dest.down()).getBlock();
if (ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
@ -195,18 +216,18 @@ public class MovementTraverse extends Movement {
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), against1) && Minecraft.getMinecraft().player.isSneaking()) {
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 {
// 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());
return state;
return state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
}
}
state.setInput(InputOverrideHandler.Input.SNEAK, true);
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);
if (!MovementHelper.throwaway(true)) {// get ready to place a throwaway block
displayChatMessageRaw("bb pls get me some blocks. dirt or cobble");

View File

@ -146,7 +146,7 @@ public interface IPath extends Helper {
}
double factor = Baritone.settings().pathCutoffFactor.get();
int newLength = (int) (length() * factor);
displayChatMessageRaw("Static cutoff " + length() + " to " + newLength);
//displayChatMessageRaw("Static cutoff " + length() + " to " + newLength);
return new CutoffPath(this, newLength);
}
}

View File

@ -22,6 +22,9 @@ import baritone.event.events.TickEvent;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.Movement;
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.Helper;
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
if (whereAmI.equals(path.positions().get(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
for (int j = pathPosition; j <= previousPos; j++) {
path.movements().get(j).reset();
}
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
return false;
}
@ -207,6 +214,15 @@ public class PathExecutor implements Helper {
if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition;
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();
if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
@ -224,6 +240,7 @@ public class PathExecutor implements Helper {
onTick(event);
return true;
} else {
sprintIfRequested();
ticksOnCurrent++;
if (ticksOnCurrent > currentMovementInitialCostEstimate + Baritone.settings().movementTimeoutTicks.get()) {
// 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
}
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() {
return pathPosition;
}

View File

@ -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;
}
}

View File

@ -18,7 +18,7 @@
package baritone.utils;
import baritone.Baritone;
import baritone.chunk.CachedWorld;
import baritone.chunk.WorldData;
import baritone.chunk.WorldProvider;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
@ -42,16 +42,15 @@ public class BlockStateInterface implements Helper {
return chunk.getBlockState(pos);
}
}
if (Baritone.settings().chunkCaching.get()) {
CachedWorld world = WorldProvider.INSTANCE.getCurrentWorld().cache;
if (world != null) {
IBlockState type = world.getBlock(pos);
if (type != null) {
return type;
}
WorldData world = WorldProvider.INSTANCE.getCurrentWorld();
if (world != null) {
IBlockState type = world.cache.getBlock(pos);
if (type != null) {
return type;
}
}
return Blocks.AIR.getDefaultState();
}

View File

@ -21,23 +21,23 @@ import baritone.Baritone;
import baritone.Settings;
import baritone.behavior.Behavior;
import baritone.behavior.impl.PathingBehavior;
import baritone.chunk.ChunkPacker;
import baritone.chunk.Waypoint;
import baritone.chunk.WorldProvider;
import baritone.event.events.ChatEvent;
import baritone.map.Map;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.goals.Goal;
import baritone.pathing.goals.GoalBlock;
import baritone.pathing.goals.GoalXZ;
import baritone.pathing.goals.GoalYLevel;
import baritone.pathing.goals.*;
import baritone.pathing.movement.ActionCosts;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
public class ExampleBaritoneControl extends Behavior {
public static ExampleBaritoneControl INSTANCE = new ExampleBaritoneControl();
@ -56,7 +56,10 @@ public class ExampleBaritoneControl extends Behavior {
return;
}
String msg = event.getMessage();
if (msg.startsWith("/")) {
if (Baritone.settings().prefix.get()) {
if (!msg.startsWith("#")) {
return;
}
msg = msg.substring(1);
}
if (msg.toLowerCase().startsWith("goal")) {
@ -107,6 +110,79 @@ public class ExampleBaritoneControl extends Behavior {
displayChatMessageRaw("ok canceled");
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")) {
Goal goal = GoalXZ.fromDirection(playerFeetAsVec(), player().rotationYaw, Double.parseDouble(msg.substring(7).trim()));
PathingBehavior.INSTANCE.setGoal(goal);
@ -114,18 +190,90 @@ public class ExampleBaritoneControl extends Behavior {
event.cancel();
return;
}
if (msg.toLowerCase().equals("spawn")) {
BlockPos spawnPoint = player().getBedLocation();
// for some reason the default spawnpoint is underground sometimes
Goal goal = new GoalXZ(spawnPoint.getX(), spawnPoint.getY());
if (msg.toLowerCase().startsWith("list") || msg.toLowerCase().startsWith("get ") || msg.toLowerCase().startsWith("show")) {
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;
}
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);
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();
return;
}
if (msg.toLowerCase().equals("costs")) {
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())));
for (Movement move : moves) {
String[] parts = move.getClass().toString().split("\\.");

View File

@ -20,16 +20,12 @@ package baritone.utils;
import baritone.Baritone;
import net.minecraft.client.Minecraft;
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.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import java.util.List;
import net.minecraft.util.text.TextFormatting;
/**
* @author Brady
@ -37,6 +33,8 @@ import java.util.List;
*/
public interface Helper {
ITextComponent MESSAGE_PREFIX = new TextComponentString("§5[§dBaritone§5]§7");
Minecraft mc = Minecraft.getMinecraft();
default EntityPlayerSP player() {
@ -73,14 +71,10 @@ public interface Helper {
System.out.println(message);
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);
}
}

View File

@ -84,8 +84,6 @@ public final class InputOverrideHandler implements Helper {
* @param forced Whether or not the state is being forced
*/
public final void setInputForceState(Input input, boolean forced) {
if (!forced)
System.out.println(input);
inputForceStateMap.put(input.getKeyBinding(), forced);
}

View File

@ -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;
}
}

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
* 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)
@ -96,7 +102,7 @@ public class ToolSet implements Helper {
* @return get which tool on the hotbar is best for mining it
*/
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
*/
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
*/
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
byte slot = this.getBestSlot(state);

View File

@ -1,13 +1,14 @@
{
"required": true,
"package": "baritone.launch.mixins",
"refmap": "mixins.client.refmap.json",
"refmap": "mixins.baritone.refmap.json",
"compatibilityLevel": "JAVA_8",
"verbose": false,
"injectors": {
"maxShiftBy": 2
},
"client": [
"MixinBlockPos",
"MixinEntity",
"MixinEntityPlayerSP",
"MixinEntityRenderer",
@ -16,7 +17,6 @@
"MixinGuiScreen",
"MixinInventoryPlayer",
"MixinKeyBinding",
"MixinMain",
"MixinMinecraft",
"MixinNetHandlerPlayClient",
"MixinNetworkManager",

View File

@ -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);
}
}
}
}
}