Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e1d827819 | ||
|
|
413e505683 | ||
|
|
0f1edba5f1 | ||
|
|
336154fd9b | ||
|
|
0ee14b4b90 | ||
|
|
5a9e5cdac4 | ||
|
|
10bb177664 | ||
|
|
69762bf4b4 | ||
|
|
e17cc79cb3 | ||
|
|
60c29fd159 | ||
|
|
7481c98dbc | ||
|
|
796b45601e | ||
|
|
b5347cebc3 | ||
|
|
65ce5ca752 | ||
|
|
d1e62ef8f2 | ||
|
|
db8daf4c59 | ||
|
|
80240cb9f2 | ||
|
|
4da0731664 | ||
|
|
af357d4d8e | ||
|
|
8c76573395 | ||
|
|
939e9c32d5 | ||
|
|
e4ef659756 | ||
|
|
4b61452c62 | ||
|
|
d5130aa6ba | ||
|
|
6c9f317f31 | ||
|
|
1ab5609d4e |
11
FEATURES.md
11
FEATURES.md
@@ -10,13 +10,16 @@
|
||||
- **Falling blocks** Baritone understands the costs of breaking blocks with falling blocks on top, and includes all of their break costs. Additionally, since it avoids breaking any blocks touching a liquid, it won't break the bottom of a gravel stack below a lava lake (anymore).
|
||||
- **Avoiding dangerous blocks** Obviously, it knows not to walk through fire or on magma, not to corner over lava (that deals some damage), not to break any blocks touching a liquid (it might drown), etc.
|
||||
- **Parkour** Sprint jumping over 1, 2, or 3 block gaps
|
||||
- **Parkour place** Sprint jumping over a 3 block gap and placing the block to land on while executing the jump. It's really cool.
|
||||
|
||||
# Pathing method
|
||||
Baritone uses a modified version of A*.
|
||||
Baritone uses A*, with some modifications:
|
||||
|
||||
- **Incremental cost backoff** Since most of the time Baritone only knows the terrain up to the render distance, it can't calculate a full path to the goal. Therefore it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit">write-up</a> that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
|
||||
- **Segmented calculation** Traditional A* calculates until the most promising node is in the goal, however in the environment of Minecraft with a limited render distance, we don't know the environment all the way to our goal. Baritone has three possible ways for path calculation to end: finding a path all the way to the goal, running out of time, or getting to the render distance. In the latter two scenarios, the selection of which segment to actually execute falls to the next item (incremental cost backoff). Whenever the path calculation thread finds that the best / most promising node is at the edge of loaded chunks, it increments a counter. If this happens more than 50 times (configurable), path calculation exits early. This happens with very low render distances. Otherwise, calculation continues until the timeout is hit (also configurable) or we find a path all the way to the goal.
|
||||
- **Incremental cost backoff** When path calculation exits early without getting all the way to the goal, Baritone it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit">write-up</a> that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
|
||||
- **Minimum improvement repropagation** The pathfinder ignores alternate routes that provide minimal improvements (less than 0.01 ticks of improvement), because the calculation cost of repropagating this to all connected nodes is much higher than the half-millisecond path time improvement it would get.
|
||||
- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment slightly, as a tiebreaker. This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. <a href="https://www.youtube.com/watch?v=CGiMcb8-99Y">Example</a>
|
||||
- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment. The cost is decreased heavily, but is still positive (this won't cause it to backtrack if it doesn't need to). This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. <a href="https://www.youtube.com/watch?v=CGiMcb8-99Y">Example</a>
|
||||
- **Backtrack detection and pausing** While path calculation happens on a separate thread, the main game thread has access to the latest node considered, and the best path so far (those are rendered light blue and dark blue respectively). When the current best path (rendered dark blue) passes through the player's current position on the current path segment, path execution is paused (if it's safe to do so), because there's no point continuing forward if we're about to turn around and go back that same way. Note that the current best path as reported by the path calculation thread takes into account the incremental cost backoff system, so it's accurate to what the path calculation thread will actually pick once it finishes.
|
||||
|
||||
# Configuring Baritone
|
||||
All the settings and documentation are <a href="https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/Settings.java">here</a>.
|
||||
@@ -30,6 +33,7 @@ The pathing goal can be set to any of these options:
|
||||
- **GoalTwoBlocks** a block position that the player should stand in, either at foot or eye level
|
||||
- **GoalGetToBlock** a block position that the player should stand adjacent to, below, or on top of
|
||||
- **GoalNear** a block position that the player should get within a certain radius of, used for following entities
|
||||
- **GoalAxis** a block position on an axis or diagonal axis (so x=0, z=0, or x=z), and y=120 (configurable)
|
||||
|
||||
And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one of which satisfies the goal. For example, `mine diamond_ore` creates a `GoalComposite` of `GoalTwoBlocks`s for every diamond ore location it knows of.
|
||||
|
||||
@@ -38,7 +42,6 @@ And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one o
|
||||
Things it doesn't have yet
|
||||
- Trapdoors
|
||||
- Sprint jumping in a 1x2 corridor
|
||||
- Parkour (jumping over gaps of any length) [IN PROGRESS]
|
||||
|
||||
See <a href="https://github.com/cabaletta/baritone/issues">issues</a> for more.
|
||||
|
||||
|
||||
@@ -18,6 +18,8 @@ For Impact 4.3, there is no Baritone integration yet, so you will want `baritone
|
||||
|
||||
Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`.
|
||||
|
||||
The build for `baritone-unoptimized-X.Y.Z.jar` is deterministic, and you can verify Travis did it properly by running `scripts/build.sh` yourself and comparing the shasum. The proguarded files (api and standalone) aren't yet reproducible, because proguard annoyingly includes the current timestamp into the final jar.
|
||||
|
||||
### Building Baritone yourself
|
||||
There are a few steps to this
|
||||
- Clone this repository
|
||||
|
||||
38
build.gradle
38
build.gradle
@@ -1,3 +1,7 @@
|
||||
import java.util.jar.JarEntry
|
||||
import java.util.jar.JarFile
|
||||
import java.util.jar.JarOutputStream
|
||||
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
@@ -16,7 +20,7 @@
|
||||
*/
|
||||
|
||||
group 'baritone'
|
||||
version '0.0.6'
|
||||
version '0.0.7'
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
@@ -88,4 +92,36 @@ mixin {
|
||||
|
||||
jar {
|
||||
from sourceSets.launch.output, sourceSets.api.output
|
||||
preserveFileTimestamps = false
|
||||
reproducibleFileOrder = true
|
||||
}
|
||||
|
||||
build {
|
||||
// while "jar" supports preserveFileTimestamps false
|
||||
// reobfJar doesn't, it just sets all the last modified times to that instant where it runs the reobfuscator
|
||||
// so we have to set all those last modified times back to zero
|
||||
doLast {
|
||||
File jarFile = new File("build/libs/baritone-" + version + ".jar")
|
||||
JarFile jf = new JarFile(jarFile)
|
||||
JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File("temp.jar")))
|
||||
jf.entries().unique { it.name }.sort { it.name }.each {
|
||||
if (it.name != "META-INF/fml_cache_annotation.json" && it.name != "META-INF/fml_cache_class_versions.json") {
|
||||
JarEntry clone = new JarEntry(it)
|
||||
clone.time = 0
|
||||
jos.putNextEntry(clone)
|
||||
copy(jf.getInputStream(it), jos)
|
||||
}
|
||||
}
|
||||
jos.finish()
|
||||
jf.close()
|
||||
file("temp.jar").renameTo(jarFile)
|
||||
}
|
||||
}
|
||||
|
||||
void copy(InputStream is, OutputStream os) {
|
||||
byte[] buffer = new byte[1024]
|
||||
int len = 0
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
os.write(buffer, 0, len)
|
||||
}
|
||||
}
|
||||
|
||||
2
scripts/proguard.pro
vendored
2
scripts/proguard.pro
vendored
@@ -1,4 +1,4 @@
|
||||
-injars baritone-0.0.6.jar
|
||||
-injars baritone-0.0.7.jar
|
||||
-outjars Obfuscated
|
||||
|
||||
|
||||
|
||||
@@ -19,6 +19,9 @@ package baritone.api;
|
||||
|
||||
import baritone.api.behavior.*;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.event.listener.IGameEventListener;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.ServiceLoader;
|
||||
@@ -42,6 +45,7 @@ public final class BaritoneAPI {
|
||||
baritone = instances.next();
|
||||
|
||||
settings = new Settings();
|
||||
SettingsUtil.readAndApply(settings);
|
||||
}
|
||||
|
||||
public static IFollowBehavior getFollowBehavior() {
|
||||
@@ -71,4 +75,12 @@ public final class BaritoneAPI {
|
||||
public static IWorldProvider getWorldProvider() {
|
||||
return baritone.getWorldProvider();
|
||||
}
|
||||
|
||||
public static IWorldScanner getWorldScanner() {
|
||||
return baritone.getWorldScanner();
|
||||
}
|
||||
|
||||
public static void registerEventListener(IGameEventListener listener) {
|
||||
baritone.registerEventListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ package baritone.api;
|
||||
|
||||
import baritone.api.behavior.*;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.event.listener.IGameEventListener;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -67,4 +69,18 @@ public interface IBaritoneProvider {
|
||||
* @return The {@link IWorldProvider} instance
|
||||
*/
|
||||
IWorldProvider getWorldProvider();
|
||||
|
||||
/**
|
||||
* @see IWorldScanner
|
||||
*
|
||||
* @return The {@link IWorldScanner} instance
|
||||
*/
|
||||
IWorldScanner getWorldScanner();
|
||||
|
||||
/**
|
||||
* Registers a {@link IGameEventListener} with Baritone's "event bus".
|
||||
*
|
||||
* @param listener The listener
|
||||
*/
|
||||
void registerEventListener(IGameEventListener listener);
|
||||
}
|
||||
|
||||
@@ -302,6 +302,11 @@ public class Settings {
|
||||
*/
|
||||
public Setting<Boolean> renderGoal = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Ignore depth when rendering the goal
|
||||
*/
|
||||
public Setting<Boolean> renderGoalIgnoreDepth = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Line width of the path when rendered, in pixels
|
||||
*/
|
||||
@@ -480,11 +485,19 @@ public class Settings {
|
||||
*/
|
||||
public Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
|
||||
|
||||
/**
|
||||
* A map of lowercase setting field names to their respective setting
|
||||
*/
|
||||
public final Map<String, Setting<?>> byLowerName;
|
||||
|
||||
/**
|
||||
* A list of all settings
|
||||
*/
|
||||
public final List<Setting<?>> allSettings;
|
||||
|
||||
public class Setting<T> {
|
||||
public T value;
|
||||
public final T defaultValue;
|
||||
private String name;
|
||||
private final Class<T> klass;
|
||||
|
||||
@@ -494,6 +507,7 @@ public class Settings {
|
||||
throw new IllegalArgumentException("Cannot determine value type class from null");
|
||||
}
|
||||
this.value = value;
|
||||
this.defaultValue = value;
|
||||
this.klass = (Class<T>) value.getClass();
|
||||
}
|
||||
|
||||
|
||||
42
src/api/java/baritone/api/cache/IWorldScanner.java
vendored
Normal file
42
src/api/java/baritone/api/cache/IWorldScanner.java
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.cache;
|
||||
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 10/6/2018
|
||||
*/
|
||||
public interface IWorldScanner {
|
||||
|
||||
/**
|
||||
* Scans the world, up to the specified max chunk radius, for the specified blocks.
|
||||
*
|
||||
* @param blocks The blocks to scan for
|
||||
* @param max The maximum number of blocks to scan before cutoff
|
||||
* @param yLevelThreshold If a block is found within this Y level, the current result will be
|
||||
* returned, if the value is negative, then this condition doesn't apply.
|
||||
* @param maxSearchRadius The maximum chunk search radius
|
||||
* @return The matching block positions
|
||||
*/
|
||||
List<BlockPos> scanLoadedChunks(List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius);
|
||||
}
|
||||
140
src/api/java/baritone/api/utils/SettingsUtil.java
Normal file
140
src/api/java/baritone/api/utils/SettingsUtil.java
Normal file
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.utils;
|
||||
|
||||
import baritone.api.Settings;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.item.Item;
|
||||
import net.minecraft.util.ResourceLocation;
|
||||
|
||||
import java.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.util.*;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class SettingsUtil {
|
||||
private static final File settingsFile = new File(new File(Minecraft.getMinecraft().gameDir, "baritone"), "settings.txt");
|
||||
|
||||
private static final Map<Class<?>, SettingsIO> map;
|
||||
|
||||
public static void readAndApply(Settings settings) {
|
||||
try (Scanner scan = new Scanner(settingsFile)) {
|
||||
while (scan.hasNextLine()) {
|
||||
String line = scan.nextLine();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith("#") || line.startsWith("//")) {
|
||||
continue;
|
||||
}
|
||||
int space = line.indexOf(" ");
|
||||
if (space == -1) {
|
||||
System.out.println("Skipping invalid line with no space: " + line);
|
||||
continue;
|
||||
}
|
||||
String settingName = line.substring(0, space).trim().toLowerCase();
|
||||
String settingValue = line.substring(space).trim();
|
||||
try {
|
||||
parseAndApply(settings, settingName, settingValue);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Unable to parse line " + line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void save(Settings settings) {
|
||||
try (FileOutputStream out = new FileOutputStream(settingsFile)) {
|
||||
for (Settings.Setting setting : settings.allSettings) {
|
||||
if (setting.get() == null) {
|
||||
System.out.println("NULL SETTING?" + setting.getName());
|
||||
continue;
|
||||
}
|
||||
if (setting.getName().equals("logger")) {
|
||||
continue; // NO
|
||||
}
|
||||
if (setting.value == setting.defaultValue) {
|
||||
continue;
|
||||
}
|
||||
SettingsIO io = map.get(setting.getValueClass());
|
||||
if (io == null) {
|
||||
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName());
|
||||
}
|
||||
out.write((setting.getName() + " " + io.toString.apply(setting.get()) + "\n").getBytes());
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Exception while saving Baritone settings!");
|
||||
}
|
||||
}
|
||||
|
||||
private static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
|
||||
Settings.Setting setting = settings.byLowerName.get(settingName);
|
||||
if (setting == null) {
|
||||
throw new IllegalStateException("No setting by that name");
|
||||
}
|
||||
Class intendedType = setting.getValueClass();
|
||||
SettingsIO ioMethod = map.get(intendedType);
|
||||
Object parsed = ioMethod.parser.apply(settingValue);
|
||||
if (!intendedType.isInstance(parsed)) {
|
||||
throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass());
|
||||
}
|
||||
setting.value = parsed;
|
||||
}
|
||||
|
||||
private enum SettingsIO {
|
||||
DOUBLE(Double.class, Double::parseDouble),
|
||||
BOOLEAN(Boolean.class, Boolean::parseBoolean),
|
||||
INTEGER(Integer.class, Integer::parseInt),
|
||||
FLOAT(Float.class, Float::parseFloat),
|
||||
LONG(Long.class, Long::parseLong),
|
||||
|
||||
ITEM_LIST(ArrayList.class, str -> Stream.of(str.split(",")).map(Item::getByNameOrId).collect(Collectors.toCollection(ArrayList::new)), list -> ((ArrayList<Item>) list).stream().map(Item.REGISTRY::getNameForObject).map(ResourceLocation::toString).collect(Collectors.joining(","))),
|
||||
COLOR(Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), color -> color.getRed() + "," + color.getGreen() + "," + color.getBlue());
|
||||
|
||||
|
||||
Class<?> klass;
|
||||
Function<String, Object> parser;
|
||||
Function<Object, String> toString;
|
||||
|
||||
<T> SettingsIO(Class<T> klass, Function<String, T> parser) {
|
||||
this(klass, parser, Object::toString);
|
||||
}
|
||||
|
||||
<T> SettingsIO(Class<T> klass, Function<String, T> parser, Function<T, String> toString) {
|
||||
this.klass = klass;
|
||||
this.parser = parser::apply;
|
||||
this.toString = x -> toString.apply((T) x);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
HashMap<Class<?>, SettingsIO> tempMap = new HashMap<>();
|
||||
for (SettingsIO type : SettingsIO.values()) {
|
||||
tempMap.put(type.klass, type);
|
||||
}
|
||||
map = Collections.unmodifiableMap(tempMap);
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,6 @@ import baritone.api.BaritoneAPI;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.event.listener.IGameEventListener;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.event.GameEventHandler;
|
||||
import baritone.utils.BaritoneAutoTest;
|
||||
import baritone.utils.InputOverrideHandler;
|
||||
@@ -36,7 +35,6 @@ import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -61,19 +59,13 @@ public enum Baritone {
|
||||
private File dir;
|
||||
private ThreadPoolExecutor threadPool;
|
||||
|
||||
|
||||
/**
|
||||
* List of consumers to be called after Baritone has initialized
|
||||
*/
|
||||
private List<Consumer<Baritone>> onInitConsumers;
|
||||
|
||||
/**
|
||||
* Whether or not Baritone is active
|
||||
*/
|
||||
private boolean active;
|
||||
|
||||
Baritone() {
|
||||
this.onInitConsumers = new ArrayList<>();
|
||||
this.gameEventHandler = new GameEventHandler();
|
||||
}
|
||||
|
||||
public synchronized void init() {
|
||||
@@ -81,7 +73,6 @@ public enum Baritone {
|
||||
return;
|
||||
}
|
||||
this.threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
|
||||
this.gameEventHandler = new GameEventHandler();
|
||||
this.inputOverrideHandler = new InputOverrideHandler();
|
||||
|
||||
// Acquire the "singleton" instance of the settings directly from the API
|
||||
@@ -109,8 +100,6 @@ public enum Baritone {
|
||||
|
||||
this.active = true;
|
||||
this.initialized = true;
|
||||
|
||||
this.onInitConsumers.forEach(consumer -> consumer.accept(this));
|
||||
}
|
||||
|
||||
public boolean isInitialized() {
|
||||
@@ -157,8 +146,4 @@ public enum Baritone {
|
||||
public File getDir() {
|
||||
return this.dir;
|
||||
}
|
||||
|
||||
public void registerInitListener(Consumer<Baritone> runnable) {
|
||||
this.onInitConsumers.add(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,8 +20,11 @@ package baritone;
|
||||
import baritone.api.IBaritoneProvider;
|
||||
import baritone.api.behavior.*;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.event.listener.IGameEventListener;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.cache.WorldScanner;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@@ -58,4 +61,14 @@ public final class BaritoneProvider implements IBaritoneProvider {
|
||||
public IWorldProvider getWorldProvider() {
|
||||
return WorldProvider.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWorldScanner getWorldScanner() {
|
||||
return WorldScanner.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerEventListener(IGameEventListener listener) {
|
||||
Baritone.INSTANCE.registerEventListener(listener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
|
||||
private MemoryBehavior() {}
|
||||
|
||||
@Override
|
||||
public void onPlayerUpdate(PlayerUpdateEvent event) {
|
||||
public synchronized void onPlayerUpdate(PlayerUpdateEvent event) {
|
||||
if (event.getState() == EventState.PRE) {
|
||||
updateInventory();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendPacket(PacketEvent event) {
|
||||
public synchronized void onSendPacket(PacketEvent event) {
|
||||
Packet p = event.getPacket();
|
||||
|
||||
if (event.getState() == EventState.PRE) {
|
||||
@@ -83,7 +83,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceivePacket(PacketEvent event) {
|
||||
public synchronized void onReceivePacket(PacketEvent event) {
|
||||
Packet p = event.getPacket();
|
||||
|
||||
if (event.getState() == EventState.PRE) {
|
||||
@@ -130,13 +130,14 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
|
||||
}
|
||||
|
||||
@Override
|
||||
public final RememberedInventory getInventoryByPos(BlockPos pos) {
|
||||
public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
|
||||
return this.getCurrentContainer().rememberedInventories.get(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Map<BlockPos, IRememberedInventory> getRememberedInventories() {
|
||||
return Collections.unmodifiableMap(this.getCurrentContainer().rememberedInventories);
|
||||
public final synchronized Map<BlockPos, IRememberedInventory> getRememberedInventories() {
|
||||
// make a copy since this map is modified from the packet thread
|
||||
return new HashMap<>(this.getCurrentContainer().rememberedInventories);
|
||||
}
|
||||
|
||||
private static final class WorldDataContainer {
|
||||
@@ -213,7 +214,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
|
||||
|
||||
@Override
|
||||
public final List<ItemStack> getContents() {
|
||||
return this.items;
|
||||
return Collections.unmodifiableList(this.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -42,7 +42,6 @@ import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
@@ -388,56 +387,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
|
||||
@Override
|
||||
public void onRenderPass(RenderEvent event) {
|
||||
// System.out.println("Render passing");
|
||||
// System.out.println(event.getPartialTicks());
|
||||
float partialTicks = event.getPartialTicks();
|
||||
if (goal != null && Baritone.settings().renderGoal.value) {
|
||||
PathRenderer.drawLitDankGoalBox(player(), goal, partialTicks, Baritone.settings().colorGoalBox.get());
|
||||
}
|
||||
if (!Baritone.settings().renderPath.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//long start = System.nanoTime();
|
||||
|
||||
|
||||
PathExecutor current = this.current; // this should prevent most race conditions?
|
||||
PathExecutor next = this.next; // like, now it's not possible for current!=null to be true, then suddenly false because of another thread
|
||||
// TODO is this enough, or do we need to acquire a lock here?
|
||||
// TODO benchmark synchronized in render loop
|
||||
|
||||
// Render the current path, if there is one
|
||||
if (current != null && current.getPath() != null) {
|
||||
int renderBegin = Math.max(current.getPosition() - 3, 0);
|
||||
PathRenderer.drawPath(current.getPath(), renderBegin, player(), partialTicks, Baritone.settings().colorCurrentPath.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
}
|
||||
if (next != null && next.getPath() != null) {
|
||||
PathRenderer.drawPath(next.getPath(), 0, player(), partialTicks, Baritone.settings().colorNextPath.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
}
|
||||
|
||||
//long split = System.nanoTime();
|
||||
if (current != null) {
|
||||
PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get());
|
||||
PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get());
|
||||
PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get());
|
||||
}
|
||||
|
||||
// If there is a path calculation currently running, render the path calculation process
|
||||
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
|
||||
currentlyRunning.bestPathSoFar().ifPresent(p -> {
|
||||
PathRenderer.drawPath(p, 0, player(), partialTicks, Baritone.settings().colorBestPathSoFar.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
});
|
||||
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
|
||||
|
||||
PathRenderer.drawPath(mr, 0, player(), partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
PathRenderer.drawManySelectionBoxes(player(), Collections.singletonList(mr.getDest()), partialTicks, Baritone.settings().colorMostRecentConsidered.get());
|
||||
});
|
||||
});
|
||||
//long end = System.nanoTime();
|
||||
//System.out.println((end - split) + " " + (split - start));
|
||||
// if (end - start > 0) {
|
||||
// System.out.println("Frame took " + (split - start) + " " + (end - split));
|
||||
//}
|
||||
PathRenderer.render(event, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -142,7 +142,11 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
||||
public final void save() {
|
||||
if (!Baritone.settings().chunkCaching.get()) {
|
||||
System.out.println("Not saving to disk; chunk caching is disabled.");
|
||||
allRegions().forEach(CachedRegion::removeExpired); // even if we aren't saving to disk, still delete expired old chunks from RAM
|
||||
allRegions().forEach(region -> {
|
||||
if (region != null) {
|
||||
region.removeExpired();
|
||||
}
|
||||
}); // even if we aren't saving to disk, still delete expired old chunks from RAM
|
||||
return;
|
||||
}
|
||||
long start = System.nanoTime() / 1000000L;
|
||||
|
||||
15
src/main/java/baritone/cache/WorldScanner.java
vendored
15
src/main/java/baritone/cache/WorldScanner.java
vendored
@@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.cache;
|
||||
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.utils.Helper;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
@@ -29,19 +30,11 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
public enum WorldScanner implements Helper {
|
||||
public enum WorldScanner implements IWorldScanner, Helper {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* Scans the world, up to your render distance, for the specified blocks.
|
||||
*
|
||||
* @param blocks The blocks to scan for
|
||||
* @param max The maximum number of blocks to scan before cutoff
|
||||
* @param yLevelThreshold If a block is found within this Y level, the current result will be
|
||||
* returned, if the value is negative, then this condition doesn't apply.
|
||||
* @param maxSearchRadius The maximum chunk search radius
|
||||
* @return The matching block positions
|
||||
*/
|
||||
@Override
|
||||
public List<BlockPos> scanLoadedChunks(List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius) {
|
||||
if (blocks.contains(null)) {
|
||||
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString());
|
||||
|
||||
@@ -139,11 +139,12 @@ class Path implements IPath {
|
||||
for (Moves moves : Moves.values()) {
|
||||
Movement move = moves.apply0(src);
|
||||
if (move.getDest().equals(dest)) {
|
||||
// TODO instead of recalculating here, could we take pathNode.cost - pathNode.prevNode.cost to get the cost as-calculated?
|
||||
move.recalculateCost(); // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution
|
||||
return move;
|
||||
}
|
||||
}
|
||||
// leave this as IllegalStateException; it's caught in AbstractNodeCostSearch
|
||||
// this is no longer called from bestPathSoFar, now it's in postprocessing
|
||||
throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src));
|
||||
}
|
||||
|
||||
|
||||
@@ -114,7 +114,9 @@ public class MovementFall extends Movement {
|
||||
|
||||
@Override
|
||||
public boolean safeToCancel(MovementState state) {
|
||||
return state.getStatus() != MovementStatus.RUNNING;
|
||||
// if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall
|
||||
// then it's safe to cancel this
|
||||
return playerFeet().equals(src) || state.getStatus() != MovementStatus.RUNNING;
|
||||
}
|
||||
|
||||
private static BetterBlockPos[] buildPositionsToBreak(BetterBlockPos src, BetterBlockPos dest) {
|
||||
|
||||
@@ -18,15 +18,13 @@
|
||||
package baritone.pathing.movement.movements;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.behavior.LookBehaviorUtils;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.Movement;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.movement.MovementState;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.Helper;
|
||||
import baritone.utils.InputOverrideHandler;
|
||||
import baritone.utils.Utils;
|
||||
import baritone.utils.*;
|
||||
import baritone.utils.pathing.BetterBlockPos;
|
||||
import baritone.utils.pathing.MutableMoveResult;
|
||||
import net.minecraft.block.Block;
|
||||
@@ -35,6 +33,7 @@ import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.Objects;
|
||||
@@ -164,6 +163,14 @@ public class MovementParkour extends Movement {
|
||||
return res.cost;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean safeToCancel(MovementState state) {
|
||||
// once this movement is instantiated, the state is default to PREPPING
|
||||
// but once it's ticked for the first time it changes to RUNNING
|
||||
// since we don't really know anything about momentum, it suffices to say Parkour can only be canceled on the 0th tick
|
||||
return state.getStatus() != MovementState.MovementStatus.RUNNING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MovementState updateState(MovementState state) {
|
||||
super.updateState(state);
|
||||
@@ -201,10 +208,13 @@ public class MovementParkour extends Movement {
|
||||
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
|
||||
double faceY = (dest.getY() + against1.getY()) * 0.5D;
|
||||
double faceZ = (dest.getZ() + against1.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;
|
||||
|
||||
Rotation place = Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations());
|
||||
RayTraceResult res = RayTraceUtils.rayTraceTowards(place);
|
||||
if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(dest.down())) {
|
||||
state.setTarget(new MovementState.MovementTarget(place, true));
|
||||
}
|
||||
LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
|
||||
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
|
||||
if (Objects.equals(selectedBlock, against1) && selectedBlock.offset(side).equals(dest.down())) {
|
||||
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
|
||||
}
|
||||
@@ -214,7 +224,7 @@ public class MovementParkour extends Movement {
|
||||
}
|
||||
|
||||
state.setInput(InputOverrideHandler.Input.JUMP, true);
|
||||
} else {
|
||||
} else if(!playerFeet().equals(dest.offset(direction, -1))) {
|
||||
state.setInput(InputOverrideHandler.Input.SPRINT, false);
|
||||
if (playerFeet().equals(src.offset(direction, -1))) {
|
||||
MovementHelper.moveTowards(state, src);
|
||||
|
||||
@@ -319,6 +319,14 @@ public class MovementTraverse extends Movement {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean safeToCancel(MovementState state) {
|
||||
// if we're in the process of breaking blocks before walking forwards
|
||||
// or if this isn't a sneak place (the block is already there)
|
||||
// then it's safe to cancel this
|
||||
return state.getStatus() != MovementState.MovementStatus.RUNNING || MovementHelper.canWalkOn(dest.down());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean prepared(MovementState state) {
|
||||
if (playerFeet().equals(src) || playerFeet().equals(src.down())) {
|
||||
|
||||
@@ -20,6 +20,7 @@ package baritone.pathing.path;
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.pathing.movement.ActionCosts;
|
||||
import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.Movement;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
@@ -31,9 +32,7 @@ import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
import static baritone.pathing.movement.MovementState.MovementStatus.*;
|
||||
|
||||
@@ -115,7 +114,8 @@ public class PathExecutor implements Helper {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = pathPosition + 2; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing)
|
||||
for (int i = pathPosition + 3; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing)
|
||||
// also don't check pathPosition+2 because reasons
|
||||
if (whereAmI.equals(path.positions().get(i))) {
|
||||
if (i - pathPosition > 2) {
|
||||
logDebug("Skipping forward " + (i - pathPosition) + " steps, to " + i);
|
||||
@@ -177,7 +177,7 @@ public class PathExecutor implements Helper {
|
||||
}
|
||||
}
|
||||
}*/
|
||||
long start = System.nanoTime() / 1000000L;
|
||||
//long start = System.nanoTime() / 1000000L;
|
||||
for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
|
||||
if (i < 0 || i >= path.movements().size()) {
|
||||
continue;
|
||||
@@ -213,10 +213,10 @@ public class PathExecutor implements Helper {
|
||||
toWalkInto = newWalkInto;
|
||||
recalcBP = false;
|
||||
}
|
||||
long end = System.nanoTime() / 1000000L;
|
||||
/*long end = System.nanoTime() / 1000000L;
|
||||
if (end - start > 0) {
|
||||
System.out.println("Recalculating break and place took " + (end - start) + "ms");
|
||||
}
|
||||
}*/
|
||||
Movement movement = path.movements().get(pathPosition);
|
||||
boolean canCancel = movement.safeToCancel();
|
||||
if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
|
||||
@@ -242,6 +242,10 @@ public class PathExecutor implements Helper {
|
||||
cancel();
|
||||
return true;
|
||||
}
|
||||
if (shouldPause()) {
|
||||
logDebug("Pausing since current best path is a backtrack");
|
||||
return true;
|
||||
}
|
||||
MovementState.MovementStatus movementStatus = movement.update();
|
||||
if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
|
||||
logDebug("Movement returns status " + movementStatus);
|
||||
@@ -270,6 +274,39 @@ public class PathExecutor implements Helper {
|
||||
return false; // movement is in progress
|
||||
}
|
||||
|
||||
private boolean shouldPause() {
|
||||
Optional<AbstractNodeCostSearch> current = AbstractNodeCostSearch.getCurrentlyRunning();
|
||||
if (!current.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
if (!player().onGround) {
|
||||
return false;
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(playerFeet().down())) {
|
||||
// we're in some kind of sketchy situation, maybe parkouring
|
||||
return false;
|
||||
}
|
||||
if (!MovementHelper.canWalkThrough(playerFeet()) || !MovementHelper.canWalkThrough(playerFeet().up())) {
|
||||
// suffocating?
|
||||
return false;
|
||||
}
|
||||
if (!path.movements().get(pathPosition).safeToCancel()) {
|
||||
return false;
|
||||
}
|
||||
Optional<IPath> currentBest = current.get().bestPathSoFar();
|
||||
if (!currentBest.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
List<BetterBlockPos> positions = currentBest.get().positions();
|
||||
if (positions.size() < 3) {
|
||||
return false; // not long enough yet to justify pausing, its far from certain we'll actually take this route
|
||||
}
|
||||
// the first block of the next path will always overlap
|
||||
// no need to pause our very last movement when it would have otherwise cleanly exited with MovementStatus SUCCESS
|
||||
positions = positions.subList(1, positions.size());
|
||||
return positions.contains(playerFeet());
|
||||
}
|
||||
|
||||
private boolean possiblyOffPath(Tuple<Double, BlockPos> status, double leniency) {
|
||||
double distanceFromPath = status.getFirst();
|
||||
if (distanceFromPath > leniency) {
|
||||
@@ -292,6 +329,7 @@ public class PathExecutor implements Helper {
|
||||
|
||||
// first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint
|
||||
if (!new CalculationContext().canSprint()) {
|
||||
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(InputOverrideHandler.Input.SPRINT,false);
|
||||
player().setSprinting(false);
|
||||
return;
|
||||
}
|
||||
@@ -304,6 +342,9 @@ public class PathExecutor implements Helper {
|
||||
return;
|
||||
}
|
||||
|
||||
// we'll take it from here, no need for minecraft to see we're holding down control and sprint for us
|
||||
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(InputOverrideHandler.Input.SPRINT,false);
|
||||
|
||||
// however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it
|
||||
Movement current = path.movements().get(pathPosition);
|
||||
if (current instanceof MovementDescend && pathPosition < path.length() - 2) {
|
||||
|
||||
@@ -23,6 +23,7 @@ import baritone.api.cache.IWaypoint;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.pathing.goals.*;
|
||||
import baritone.api.pathing.movement.ActionCosts;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.behavior.Behavior;
|
||||
import baritone.behavior.FollowBehavior;
|
||||
import baritone.behavior.MineBehavior;
|
||||
@@ -79,6 +80,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
||||
setting.value ^= true;
|
||||
event.cancel();
|
||||
logDirect("Toggled " + setting.getName() + " to " + setting.value);
|
||||
SettingsUtil.save(Baritone.settings());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -112,6 +114,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
||||
event.cancel();
|
||||
return;
|
||||
}
|
||||
SettingsUtil.save(Baritone.settings());
|
||||
logDirect(setting.toString());
|
||||
event.cancel();
|
||||
return;
|
||||
|
||||
@@ -18,12 +18,16 @@
|
||||
package baritone.utils;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.RenderEvent;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalComposite;
|
||||
import baritone.api.pathing.goals.GoalTwoBlocks;
|
||||
import baritone.api.pathing.goals.GoalXZ;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.path.IPath;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.utils.pathing.BetterBlockPos;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@@ -40,6 +44,7 @@ import net.minecraft.util.math.MathHelper;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static org.lwjgl.opengl.GL11.*;
|
||||
@@ -55,6 +60,61 @@ public final class PathRenderer implements Helper {
|
||||
|
||||
private PathRenderer() {}
|
||||
|
||||
public static void render(RenderEvent event, PathingBehavior behavior) {
|
||||
// System.out.println("Render passing");
|
||||
// System.out.println(event.getPartialTicks());
|
||||
float partialTicks = event.getPartialTicks();
|
||||
Goal goal = behavior.getGoal();
|
||||
EntityPlayerSP player = mc.player;
|
||||
if (goal != null && Baritone.settings().renderGoal.value) {
|
||||
PathRenderer.drawLitDankGoalBox(player, goal, partialTicks, Baritone.settings().colorGoalBox.get());
|
||||
}
|
||||
if (!Baritone.settings().renderPath.get()) {
|
||||
return;
|
||||
}
|
||||
|
||||
//long start = System.nanoTime();
|
||||
|
||||
|
||||
PathExecutor current = behavior.getCurrent(); // this should prevent most race conditions?
|
||||
PathExecutor next = behavior.getNext(); // like, now it's not possible for current!=null to be true, then suddenly false because of another thread
|
||||
// TODO is this enough, or do we need to acquire a lock here?
|
||||
// TODO benchmark synchronized in render loop
|
||||
|
||||
// Render the current path, if there is one
|
||||
if (current != null && current.getPath() != null) {
|
||||
int renderBegin = Math.max(current.getPosition() - 3, 0);
|
||||
PathRenderer.drawPath(current.getPath(), renderBegin, player, partialTicks, Baritone.settings().colorCurrentPath.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
}
|
||||
if (next != null && next.getPath() != null) {
|
||||
PathRenderer.drawPath(next.getPath(), 0, player, partialTicks, Baritone.settings().colorNextPath.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
}
|
||||
|
||||
//long split = System.nanoTime();
|
||||
if (current != null) {
|
||||
PathRenderer.drawManySelectionBoxes(player, current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get());
|
||||
PathRenderer.drawManySelectionBoxes(player, current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get());
|
||||
PathRenderer.drawManySelectionBoxes(player, current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get());
|
||||
}
|
||||
|
||||
// If there is a path calculation currently running, render the path calculation process
|
||||
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
|
||||
currentlyRunning.bestPathSoFar().ifPresent(p -> {
|
||||
PathRenderer.drawPath(p, 0, player, partialTicks, Baritone.settings().colorBestPathSoFar.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
});
|
||||
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
|
||||
|
||||
PathRenderer.drawPath(mr, 0, player, partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20);
|
||||
PathRenderer.drawManySelectionBoxes(player, Collections.singletonList(mr.getDest()), partialTicks, Baritone.settings().colorMostRecentConsidered.get());
|
||||
});
|
||||
});
|
||||
//long end = System.nanoTime();
|
||||
//System.out.println((end - split) + " " + (split - start));
|
||||
// if (end - start > 0) {
|
||||
// System.out.println("Frame took " + (split - start) + " " + (end - split));
|
||||
//}
|
||||
}
|
||||
|
||||
public static void drawPath(IPath path, int startIndex, EntityPlayerSP player, float partialTicks, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) {
|
||||
GlStateManager.enableBlend();
|
||||
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
@@ -232,26 +292,12 @@ public final class PathRenderer implements Helper {
|
||||
GlStateManager.glLineWidth(Baritone.settings().goalRenderLineWidthPixels.get());
|
||||
GlStateManager.disableTexture2D();
|
||||
GlStateManager.depthMask(false);
|
||||
|
||||
if (y1 != 0) {
|
||||
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
|
||||
BUFFER.pos(minX, y1, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y1, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y1, maxZ).endVertex();
|
||||
BUFFER.pos(minX, y1, maxZ).endVertex();
|
||||
BUFFER.pos(minX, y1, minZ).endVertex();
|
||||
TESSELLATOR.draw();
|
||||
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
|
||||
GlStateManager.disableDepth();
|
||||
}
|
||||
|
||||
if (y2 != 0) {
|
||||
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
|
||||
BUFFER.pos(minX, y2, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y2, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y2, maxZ).endVertex();
|
||||
BUFFER.pos(minX, y2, maxZ).endVertex();
|
||||
BUFFER.pos(minX, y2, minZ).endVertex();
|
||||
TESSELLATOR.draw();
|
||||
}
|
||||
renderHorizontalQuad(minX, maxX, minZ, maxZ, y1);
|
||||
renderHorizontalQuad(minX, maxX, minZ, maxZ, y2);
|
||||
|
||||
BUFFER.begin(GL_LINES, DefaultVertexFormats.POSITION);
|
||||
BUFFER.pos(minX, minY, minZ).endVertex();
|
||||
@@ -264,9 +310,22 @@ public final class PathRenderer implements Helper {
|
||||
BUFFER.pos(minX, maxY, maxZ).endVertex();
|
||||
TESSELLATOR.draw();
|
||||
|
||||
|
||||
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
|
||||
GlStateManager.enableDepth();
|
||||
}
|
||||
GlStateManager.depthMask(true);
|
||||
GlStateManager.enableTexture2D();
|
||||
GlStateManager.disableBlend();
|
||||
}
|
||||
|
||||
private static void renderHorizontalQuad(double minX, double maxX, double minZ, double maxZ, double y) {
|
||||
if (y != 0) {
|
||||
BUFFER.begin(GL_LINE_LOOP, DefaultVertexFormats.POSITION);
|
||||
BUFFER.pos(minX, y, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y, minZ).endVertex();
|
||||
BUFFER.pos(maxX, y, maxZ).endVertex();
|
||||
BUFFER.pos(minX, y, maxZ).endVertex();
|
||||
TESSELLATOR.draw();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user