forked from RepoMirrors/baritone
Merge branch 'master' into mapping
This commit is contained in:
commit
d6c766fb66
|
@ -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
|
|
@ -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'
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.behavior.impl;
|
||||
|
||||
import baritone.behavior.Behavior;
|
||||
import baritone.chunk.Waypoint;
|
||||
import baritone.chunk.WorldProvider;
|
||||
import baritone.event.events.BlockInteractEvent;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.BlockBed;
|
||||
|
||||
/**
|
||||
* A collection of event methods that are used to interact with Baritone's
|
||||
* waypoint system. This class probably needs a better name.
|
||||
*
|
||||
* @see Waypoint
|
||||
*
|
||||
* @author Brady
|
||||
* @since 8/22/2018
|
||||
*/
|
||||
public final class LocationTrackingBehavior extends Behavior {
|
||||
|
||||
public static final LocationTrackingBehavior INSTANCE = new LocationTrackingBehavior();
|
||||
|
||||
private LocationTrackingBehavior() {}
|
||||
|
||||
@Override
|
||||
public void onBlockInteract(BlockInteractEvent event) {
|
||||
if (event.getType() == BlockInteractEvent.Type.USE && BlockStateInterface.getBlock(event.getPos()) instanceof BlockBed) {
|
||||
WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("bed", Waypoint.Tag.BED, event.getPos()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerDeath() {
|
||||
WorldProvider.INSTANCE.getCurrentWorld().waypoints.addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, playerFeet()));
|
||||
}
|
||||
}
|
|
@ -58,21 +58,42 @@ public class LookBehavior extends Behavior {
|
|||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.event.events;
|
||||
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/22/2018
|
||||
*/
|
||||
public final class BlockInteractEvent {
|
||||
|
||||
/**
|
||||
* The position of the block interacted with
|
||||
*/
|
||||
private final BlockPos pos;
|
||||
|
||||
/**
|
||||
* The type of interaction that occurred
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
public BlockInteractEvent(BlockPos pos, Type type) {
|
||||
this.pos = pos;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The position of the block interacted with
|
||||
*/
|
||||
public final BlockPos getPos() {
|
||||
return this.pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of interaction with the target block
|
||||
*/
|
||||
public final Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
* We're breaking the target block.
|
||||
*/
|
||||
BREAK,
|
||||
|
||||
/**
|
||||
* We're right clicking on the target block. Either placing or interacting with.
|
||||
*/
|
||||
USE
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.event.events;
|
||||
|
||||
public enum PathEvent {
|
||||
CALC_STARTED,
|
||||
CALC_FINISHED_NOW_EXECUTING,
|
||||
CALC_FAILED,
|
||||
NEXT_SEGMENT_CALC_STARTED,
|
||||
NEXT_SEGMENT_CALC_FINISHED,
|
||||
CONTINUING_ONTO_PLANNED_NEXT,
|
||||
SPLICING_ONTO_NEXT_EARLY,
|
||||
AT_GOAL,
|
||||
PATH_FINISHED_NEXT_STILL_CALCULATING,
|
||||
NEXT_CALC_FAILED,
|
||||
DISCARD_NEXT
|
||||
}
|
|
@ -41,9 +41,8 @@ import baritone.event.events.*;
|
|||
* overridden with empty bodies, allowing inheritors of this class to choose
|
||||
* 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) {}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
83
src/main/java/baritone/launch/mixins/MixinMain.java → src/main/java/baritone/launch/mixins/MixinBlockPos.java
Executable file → Normal file
83
src/main/java/baritone/launch/mixins/MixinMain.java → src/main/java/baritone/launch/mixins/MixinBlockPos.java
Executable file → Normal 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();
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<>();
|
||||
}
|
||||
|
|
|
@ -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++) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils;
|
||||
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/25/2018
|
||||
*/
|
||||
public final class BlockBreakHelper implements Helper {
|
||||
|
||||
private BlockBreakHelper() {}
|
||||
|
||||
/**
|
||||
* The last block that we tried to break, if this value changes
|
||||
* between attempts, then we re-initialize the breaking process.
|
||||
*/
|
||||
private static BlockPos lastBlock;
|
||||
|
||||
public static void tryBreakBlock(BlockPos pos, EnumFacing side) {
|
||||
if (!pos.equals(lastBlock)) {
|
||||
mc.playerController.clickBlock(pos, side);
|
||||
}
|
||||
if (mc.playerController.onPlayerDamageBlock(pos, side)) {
|
||||
mc.player.swingArm(EnumHand.MAIN_HAND);
|
||||
}
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
public static void stopBreakingBlock() {
|
||||
mc.playerController.resetBlockRemoving();
|
||||
lastBlock = null;
|
||||
}
|
||||
}
|
|
@ -18,7 +18,7 @@
|
|||
package baritone.utils;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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("\\.");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue