mirror of https://github.com/cabaletta/baritone
Merge branch 'master' into benchmark
This commit is contained in:
commit
9ce574266f
11
README.md
11
README.md
|
@ -1,11 +1,16 @@
|
|||
# Baritone
|
||||
[![Build Status](https://travis-ci.com/cabaletta/baritone.svg?branch=master)](https://travis-ci.com/cabaletta/baritone)
|
||||
[![Release](https://img.shields.io/github/release/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/releases)
|
||||
[![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE)
|
||||
[![License](https://img.shields.io/badge/license-LGPL--3.0-green.svg)](LICENSE)
|
||||
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&utm_medium=referral&utm_content=cabaletta/baritone&utm_campaign=Badge_Grade)
|
||||
[![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone)
|
||||
[![Known Vulnerabilities](https://snyk.io/test/github/cabaletta/baritone/badge.svg?targetFile=build.gradle)](https://snyk.io/test/github/cabaletta/baritone?targetFile=build.gradle)
|
||||
[![contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues)
|
||||
[![Minecraft](https://img.shields.io/badge/MC-1.12.2-green.svg)](https://minecraft.gamepedia.com/1.12.2)
|
||||
[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.0.0--hotfix--4-brightgreen.svg)](https://impactdevelopment.github.io/)
|
||||
[![KAMI integration](https://img.shields.io/badge/KAMI%20integration-v1.0.0-orange.svg)](https://github.com/zeroeightysix/KAMI/)
|
||||
[![Asuna integration](https://img.shields.io/badge/Asuna%20integration-v1.0.0-orange.svg)](https://github.com/EmotionalLove/Asuna/)
|
||||
[![Future integration](https://img.shields.io/badge/Future%20integration-%3F%3F%3F-red.svg)](https://futureclient.net/)
|
||||
|
||||
A Minecraft pathfinder bot.
|
||||
|
||||
|
@ -20,8 +25,6 @@ Here are some links to help to get started:
|
|||
|
||||
- [Installation](INSTALL.md)
|
||||
|
||||
There's also some useful information down below
|
||||
|
||||
# Setup
|
||||
|
||||
## Command Line
|
||||
|
@ -38,7 +41,7 @@ Building Baritone:
|
|||
$ gradlew build
|
||||
```
|
||||
|
||||
For example, to replace out Impact 4.4's Baritone build with a customized one, switch to the `impact4.4-compat` branch, build Baritone as above then copy `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.0.0/baritone-api-1.0.0.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.4/1.12.2-Impact_4.4.json`, find the line `"name": "cabaletta:baritone-api:1.0.0"`, remove the comma from the end, and entirely remove the line that's immediately after (starts with `"url"`).
|
||||
To replace out Impact 4.4's Baritone build with a customized one, switch to the `impact4.4-compat` branch, build Baritone as above then copy `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.0.0/baritone-api-1.0.0.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.4/1.12.2-Impact_4.4.json`, find the line `"name": "cabaletta:baritone-api:1.0.0"`, remove the comma from the end, and entirely remove the line that's immediately after (starts with `"url"`).
|
||||
|
||||
## IntelliJ's Gradle UI
|
||||
- Open the project in IntelliJ as a Gradle project
|
||||
|
|
|
@ -98,6 +98,11 @@ mixin {
|
|||
add sourceSets.launch, 'mixins.baritone.refmap.json'
|
||||
}
|
||||
|
||||
javadoc {
|
||||
source = sourceSets.api.allJava
|
||||
classpath = sourceSets.api.compileClasspath
|
||||
}
|
||||
|
||||
jar {
|
||||
from sourceSets.launch.output, sourceSets.api.output
|
||||
preserveFileTimestamps = false
|
||||
|
@ -107,7 +112,6 @@ jar {
|
|||
task proguard(type: ProguardTask) {
|
||||
url 'https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip'
|
||||
extract 'proguard6.0.3/lib/proguard.jar'
|
||||
versionManifest 'https://launchermeta.mojang.com/mc/game/version_manifest.json'
|
||||
}
|
||||
|
||||
task createDist(type: CreateDistTask, dependsOn: proguard)
|
||||
|
|
|
@ -18,21 +18,26 @@
|
|||
package baritone.gradle.task;
|
||||
|
||||
import baritone.gradle.util.Determinizer;
|
||||
import com.google.gson.*;
|
||||
import baritone.gradle.util.MappingType;
|
||||
import baritone.gradle.util.ReobfWrapper;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.gradle.api.NamedDomainObjectContainer;
|
||||
import org.gradle.api.artifacts.Configuration;
|
||||
import org.gradle.api.artifacts.Dependency;
|
||||
import org.gradle.api.internal.plugins.DefaultConvention;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
import org.gradle.internal.Pair;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Field;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
|
@ -52,10 +57,6 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
@Input
|
||||
private String extract;
|
||||
|
||||
@Input
|
||||
private String versionManifest;
|
||||
|
||||
private Map<String, String> versionDownloadMap;
|
||||
private List<String> requiredLibraries;
|
||||
|
||||
@TaskAction
|
||||
|
@ -67,7 +68,6 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
downloadProguard();
|
||||
extractProguard();
|
||||
generateConfigs();
|
||||
downloadVersionManifest();
|
||||
acquireDependencies();
|
||||
proguardApi();
|
||||
proguardStandalone();
|
||||
|
@ -132,20 +132,6 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
});
|
||||
}
|
||||
|
||||
private void downloadVersionManifest() throws Exception {
|
||||
Path manifestJson = getTemporaryFile(VERSION_MANIFEST);
|
||||
write(new URL(this.versionManifest).openStream(), manifestJson);
|
||||
|
||||
// Place all the versions in the map with their download URL
|
||||
this.versionDownloadMap = new HashMap<>();
|
||||
JsonObject json = readJson(Files.readAllLines(manifestJson)).getAsJsonObject();
|
||||
JsonArray versions = json.getAsJsonArray("versions");
|
||||
versions.forEach(element -> {
|
||||
JsonObject object = element.getAsJsonObject();
|
||||
this.versionDownloadMap.put(object.get("id").getAsString(), object.get("url").getAsString());
|
||||
});
|
||||
}
|
||||
|
||||
private void acquireDependencies() throws Exception {
|
||||
|
||||
// Create a map of all of the dependencies that we are able to access in this project
|
||||
|
@ -163,15 +149,13 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
|
||||
// Iterate the required libraries to copy them to tempLibraries
|
||||
for (String lib : this.requiredLibraries) {
|
||||
// Download the version jar from the URL acquired from the version manifest
|
||||
if (lib.startsWith("minecraft")) {
|
||||
String version = lib.split("-")[1];
|
||||
Path versionJar = getTemporaryFile("tempLibraries/" + lib + ".jar");
|
||||
if (!Files.exists(versionJar)) {
|
||||
JsonObject versionJson = PARSER.parse(new InputStreamReader(new URL(this.versionDownloadMap.get(version)).openStream())).getAsJsonObject();
|
||||
String url = versionJson.getAsJsonObject("downloads").getAsJsonObject("client").getAsJsonPrimitive("url").getAsString();
|
||||
write(new URL(url).openStream(), versionJar);
|
||||
}
|
||||
// copy from the forgegradle cache
|
||||
if (lib.equals("minecraft")) {
|
||||
Path cachedJar = getMinecraftJar();
|
||||
Path inTempDir = getTemporaryFile("tempLibraries/minecraft.jar");
|
||||
// TODO: maybe try not to copy every time
|
||||
Files.copy(cachedJar, inTempDir, REPLACE_EXISTING);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -195,6 +179,89 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
}
|
||||
}
|
||||
|
||||
// a bunch of epic stuff to get the path to the cached jar
|
||||
private Path getMinecraftJar() throws Exception {
|
||||
MappingType mappingType;
|
||||
try {
|
||||
mappingType = getMappingType();
|
||||
} catch (Exception e) {
|
||||
System.err.println("Failed to get mapping type, assuming NOTCH.");
|
||||
mappingType = MappingType.NOTCH;
|
||||
}
|
||||
|
||||
String suffix;
|
||||
switch (mappingType) {
|
||||
case NOTCH:
|
||||
suffix = "";
|
||||
break;
|
||||
case SEARGE:
|
||||
suffix = "-srgBin";
|
||||
break;
|
||||
case CUSTOM:
|
||||
throw new IllegalStateException("Custom mappings not supported!");
|
||||
default:
|
||||
throw new IllegalStateException("Unknown mapping type: " + mappingType);
|
||||
}
|
||||
|
||||
DefaultConvention convention = (DefaultConvention) this.getProject().getConvention();
|
||||
Object extension = convention.getAsMap().get("minecraft");
|
||||
Objects.requireNonNull(extension);
|
||||
|
||||
// for some reason cant use Class.forName
|
||||
Class<?> class_baseExtension = extension.getClass().getSuperclass().getSuperclass().getSuperclass(); // <-- cursed
|
||||
Field f_replacer = class_baseExtension.getDeclaredField("replacer");
|
||||
f_replacer.setAccessible(true);
|
||||
Object replacer = f_replacer.get(extension);
|
||||
Class<?> class_replacementProvider = replacer.getClass();
|
||||
Field replacement_replaceMap = class_replacementProvider.getDeclaredField("replaceMap");
|
||||
replacement_replaceMap.setAccessible(true);
|
||||
|
||||
Map<String, Object> replacements = (Map) replacement_replaceMap.get(replacer);
|
||||
String cacheDir = replacements.get("CACHE_DIR").toString() + "/net/minecraft";
|
||||
String mcVersion = replacements.get("MC_VERSION").toString();
|
||||
String mcpInsert = replacements.get("MAPPING_CHANNEL").toString() + "/" + replacements.get("MAPPING_VERSION").toString();
|
||||
String fullJarName = "minecraft-" + mcVersion + suffix + ".jar";
|
||||
|
||||
String baseDir = String.format("%s/minecraft/%s/", cacheDir, mcVersion);
|
||||
|
||||
String jarPath;
|
||||
if (mappingType == MappingType.SEARGE) {
|
||||
jarPath = String.format("%s/%s/%s", baseDir, mcpInsert, fullJarName);
|
||||
} else {
|
||||
jarPath = baseDir + fullJarName;
|
||||
}
|
||||
jarPath = jarPath
|
||||
.replace("/", File.separator)
|
||||
.replace("\\", File.separator); // hecking regex
|
||||
|
||||
return new File(jarPath).toPath();
|
||||
}
|
||||
|
||||
// throws IllegalStateException if mapping type is ambiguous or it fails to find it
|
||||
private MappingType getMappingType() {
|
||||
// if it fails to find this then its probably a forgegradle version problem
|
||||
Set<Object> reobf = (NamedDomainObjectContainer<Object>) this.getProject().getExtensions().getByName("reobf");
|
||||
|
||||
List<MappingType> mappingTypes = getUsedMappingTypes(reobf);
|
||||
long mappingTypesUsed = mappingTypes.size();
|
||||
if (mappingTypesUsed == 0) {
|
||||
throw new IllegalStateException("Failed to find mapping type (no jar task?)");
|
||||
}
|
||||
if (mappingTypesUsed > 1) {
|
||||
throw new IllegalStateException("Ambiguous mapping type (multiple jars with different mapping types?)");
|
||||
}
|
||||
|
||||
return mappingTypes.get(0);
|
||||
}
|
||||
|
||||
private List<MappingType> getUsedMappingTypes(Set<Object> reobf) {
|
||||
return reobf.stream()
|
||||
.map(ReobfWrapper::new)
|
||||
.map(ReobfWrapper::getMappingType)
|
||||
.distinct()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private void proguardApi() throws Exception {
|
||||
runProguard(getTemporaryFile(PROGUARD_API_CONFIG));
|
||||
Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString());
|
||||
|
@ -219,10 +286,6 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
this.extract = extract;
|
||||
}
|
||||
|
||||
public void setVersionManifest(String versionManifest) {
|
||||
this.versionManifest = versionManifest;
|
||||
}
|
||||
|
||||
private void runProguard(Path config) throws Exception {
|
||||
// Delete the existing proguard output file. Proguard probably handles this already, but why not do it ourselves
|
||||
if (Files.exists(this.proguardOut)) {
|
||||
|
@ -252,7 +315,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
|||
while ((line = reader.readLine()) != null) {
|
||||
System.out.println(line);
|
||||
}
|
||||
} catch (final Exception e) {
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}).start();
|
||||
|
|
|
@ -15,13 +15,15 @@
|
|||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.utils;
|
||||
package baritone.gradle.util;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 9/23/2018
|
||||
* All credits go to AsmLibGradle and its contributors.
|
||||
*
|
||||
* @see <a href="https://github.com/pozzed/AsmLibGradle/blob/8f917dbc3939eab7a3d9daf54d9d285fdf34f4b2/src/main/java/net/futureclient/asmlib/forgegradle/MappingType.java">Original Source</a>
|
||||
*/
|
||||
public class Logger {
|
||||
|
||||
|
||||
public enum MappingType {
|
||||
SEARGE,
|
||||
NOTCH,
|
||||
CUSTOM // forgegradle
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* 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.gradle.util;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* All credits go to AsmLibGradle and its contributors.
|
||||
*
|
||||
* @see <a href="https://github.com/pozzed/AsmLibGradle/blob/8f917dbc3939eab7a3d9daf54d9d285fdf34f4b2/src/main/java/net/futureclient/asmlib/forgegradle/ReobfWrapper.java">Original Source</a>
|
||||
*/
|
||||
public class ReobfWrapper {
|
||||
|
||||
private final Object instance;
|
||||
private final Class<?> type;
|
||||
|
||||
public ReobfWrapper(Object instance) {
|
||||
this.instance = instance;
|
||||
Objects.requireNonNull(instance);
|
||||
this.type = instance.getClass();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
try {
|
||||
Field nameField = type.getDeclaredField("name");
|
||||
nameField.setAccessible(true);
|
||||
return (String) nameField.get(this.instance);
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public MappingType getMappingType() {
|
||||
try {
|
||||
Field enumField = type.getDeclaredField("mappingType");
|
||||
enumField.setAccessible(true);
|
||||
Enum<?> aEnum = (Enum<?>) enumField.get(this.instance);
|
||||
MappingType mappingType = MappingType.values()[aEnum.ordinal()];
|
||||
if (!aEnum.name().equals(mappingType.name())) {
|
||||
throw new IllegalStateException("ForgeGradle ReobfMappingType is not equivalent to MappingType (version error?)");
|
||||
}
|
||||
return mappingType;
|
||||
} catch (ReflectiveOperationException ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,7 +31,8 @@
|
|||
|
||||
# copy all necessary libraries into tempLibraries to build
|
||||
|
||||
-libraryjars 'tempLibraries/minecraft-1.12.2.jar'
|
||||
# The correct jar will be copied from the forgegradle cache based on the mapping type being compiled with
|
||||
-libraryjars 'tempLibraries/minecraft.jar'
|
||||
|
||||
-libraryjars 'tempLibraries/SimpleTweaker-1.2.jar'
|
||||
|
||||
|
|
|
@ -18,10 +18,10 @@
|
|||
package baritone.api;
|
||||
|
||||
import baritone.api.behavior.ILookBehavior;
|
||||
import baritone.api.behavior.IMemoryBehavior;
|
||||
import baritone.api.behavior.IPathingBehavior;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.pathing.calc.IPathingControlManager;
|
||||
import baritone.api.process.ICustomGoalProcess;
|
||||
import baritone.api.process.IFollowProcess;
|
||||
import baritone.api.process.IGetToBlockProcess;
|
||||
|
@ -47,12 +47,6 @@ public interface IBaritone {
|
|||
*/
|
||||
ILookBehavior getLookBehavior();
|
||||
|
||||
/**
|
||||
* @return The {@link IMemoryBehavior} instance
|
||||
* @see IMemoryBehavior
|
||||
*/
|
||||
IMemoryBehavior getMemoryBehavior();
|
||||
|
||||
/**
|
||||
* @return The {@link IMineProcess} instance
|
||||
* @see IMineProcess
|
||||
|
@ -71,6 +65,8 @@ public interface IBaritone {
|
|||
*/
|
||||
IWorldProvider getWorldProvider();
|
||||
|
||||
IPathingControlManager getPathingControlManager();
|
||||
|
||||
IInputOverrideHandler getInputOverrideHandler();
|
||||
|
||||
ICustomGoalProcess getCustomGoalProcess();
|
||||
|
|
|
@ -50,6 +50,11 @@ public class Settings {
|
|||
*/
|
||||
public Setting<Boolean> allowPlace = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Allow Baritone to move items in your inventory to your hotbar
|
||||
*/
|
||||
public Setting<Boolean> allowInventory = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* It doesn't actually take twenty ticks to place a block, this cost is so high
|
||||
* because we want to generally conserve blocks which might be limited
|
||||
|
@ -63,6 +68,16 @@ public class Settings {
|
|||
*/
|
||||
public Setting<Double> blockBreakAdditionalPenalty = new Setting<>(2D);
|
||||
|
||||
/**
|
||||
* Additional penalty for hitting the space bar (ascend, pillar, or parkour) beacuse it uses hunger
|
||||
*/
|
||||
public Setting<Double> jumpPenalty = new Setting<>(2D);
|
||||
|
||||
/**
|
||||
* Walking on water uses up hunger really quick, so penalize it
|
||||
*/
|
||||
public Setting<Double> walkOnWaterOnePenalty = new Setting<>(5D);
|
||||
|
||||
/**
|
||||
* Allow Baritone to fall arbitrary distances and place a water bucket beneath it.
|
||||
* Reliability: questionable.
|
||||
|
@ -89,6 +104,22 @@ public class Settings {
|
|||
*/
|
||||
public Setting<Boolean> assumeSafeWalk = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* If true, parkour is allowed to make jumps when standing on blocks at the maximum height, so player feet is y=256
|
||||
* <p>
|
||||
* Defaults to false because this fails on NCP
|
||||
*/
|
||||
public Setting<Boolean> allowJumpAt256 = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Allow descending diagonally
|
||||
* <p>
|
||||
* Safer than allowParkour yet still slightly unsafe, can make contact with unchecked adjacent blocks, so it's unsafe in the nether.
|
||||
* <p>
|
||||
* For a generic "take some risks" mode I'd turn on this one, parkour, and parkour place.
|
||||
*/
|
||||
public Setting<Boolean> allowDiagonalDescend = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Blocks that Baritone is allowed to place (as throwaway, for sneak bridging, pillaring, etc.)
|
||||
*/
|
||||
|
@ -142,7 +173,7 @@ public class Settings {
|
|||
* <p>
|
||||
* Finding the optimal path is worth it, so it's the default.
|
||||
*/
|
||||
public Setting<Double> costHeuristic = new Setting<>(3.5D);
|
||||
public Setting<Double> costHeuristic = new Setting<>(3.563);
|
||||
|
||||
// a bunch of obscure internal A* settings that you probably don't want to change
|
||||
/**
|
||||
|
@ -158,6 +189,42 @@ public class Settings {
|
|||
*/
|
||||
public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.5);
|
||||
|
||||
/**
|
||||
* Toggle the following 4 settings
|
||||
* <p>
|
||||
* They have a noticable performance impact, so they default off
|
||||
*/
|
||||
public Setting<Boolean> avoidance = new Setting<>(false);
|
||||
/**
|
||||
* Set to 1.0 to effectively disable this feature
|
||||
* <p>
|
||||
* Set below 1.0 to go out of your way to walk near mob spawners
|
||||
*/
|
||||
public Setting<Double> mobSpawnerAvoidanceCoefficient = new Setting<>(2.0);
|
||||
|
||||
public Setting<Integer> mobSpawnerAvoidanceRadius = new Setting<>(16);
|
||||
|
||||
/**
|
||||
* Set to 1.0 to effectively disable this feature
|
||||
* <p>
|
||||
* Set below 1.0 to go out of your way to walk near mobs
|
||||
*/
|
||||
public Setting<Double> mobAvoidanceCoefficient = new Setting<>(1.5);
|
||||
|
||||
public Setting<Integer> mobAvoidanceRadius = new Setting<>(8);
|
||||
|
||||
/**
|
||||
* When running a goto towards a container block (chest, ender chest, furnace, etc),
|
||||
* right click and open it once you arrive.
|
||||
*/
|
||||
public Setting<Boolean> rightClickContainerOnArrival = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* When running a goto towards a nether portal block, walk all the way into the portal
|
||||
* instead of stopping one block before.
|
||||
*/
|
||||
public Setting<Boolean> enterPortal = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies,
|
||||
* and there's no point.
|
||||
|
@ -328,6 +395,12 @@ public class Settings {
|
|||
*/
|
||||
public Setting<Boolean> renderGoalIgnoreDepth = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Renders X/Z type Goals with the vanilla beacon beam effect. Combining this with
|
||||
* {@link #renderGoalIgnoreDepth} will cause strange render clipping.
|
||||
*/
|
||||
public Setting<Boolean> renderGoalXZBeacon = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Ignore depth when rendering the selection boxes (to break, to place, to walk into)
|
||||
*/
|
||||
|
@ -379,10 +452,6 @@ public class Settings {
|
|||
|
||||
/**
|
||||
* {@code true}: can mine blocks when in inventory, chat, or tabbed away in ESC menu
|
||||
* <p>
|
||||
* {@code false}: works on cosmic prisons
|
||||
* <p>
|
||||
* LOL
|
||||
*/
|
||||
public Setting<Boolean> leftClickWorkaround = new Setting<>(true);
|
||||
|
||||
|
@ -553,6 +622,12 @@ public class Settings {
|
|||
*/
|
||||
public final List<Setting<?>> allSettings;
|
||||
|
||||
public void reset() {
|
||||
for (Setting setting : allSettings) {
|
||||
setting.value = setting.defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
public class Setting<T> {
|
||||
public T value;
|
||||
public final T defaultValue;
|
||||
|
|
|
@ -37,12 +37,12 @@ public interface ICachedRegion extends IBlockTypeAccess {
|
|||
boolean isCached(int blockX, int blockZ);
|
||||
|
||||
/**
|
||||
* The X coordinate of this region
|
||||
* @return The X coordinate of this region
|
||||
*/
|
||||
int getX();
|
||||
|
||||
/**
|
||||
* The Z coordinate of this region
|
||||
* @return The Z coordinate of this region
|
||||
*/
|
||||
int getZ();
|
||||
}
|
||||
|
|
|
@ -15,9 +15,8 @@
|
|||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.behavior;
|
||||
package baritone.api.cache;
|
||||
|
||||
import baritone.api.behavior.memory.IRememberedInventory;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.Map;
|
||||
|
@ -26,7 +25,7 @@ import java.util.Map;
|
|||
* @author Brady
|
||||
* @since 9/23/2018
|
||||
*/
|
||||
public interface IMemoryBehavior extends IBehavior {
|
||||
public interface IContainerMemory {
|
||||
|
||||
/**
|
||||
* Gets a remembered inventory by its block position.
|
|
@ -15,7 +15,7 @@
|
|||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.api.behavior.memory;
|
||||
package baritone.api.cache;
|
||||
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
|
@ -27,13 +27,19 @@ public interface IWorldData {
|
|||
* Returns the cached world for this world. A cached world is a simplified format
|
||||
* of a regular world, intended for use on multiplayer servers where chunks are not
|
||||
* traditionally stored to disk, allowing for long distance pathing with minimal disk usage.
|
||||
*
|
||||
* @return The cached world for this world
|
||||
*/
|
||||
ICachedWorld getCachedWorld();
|
||||
|
||||
/**
|
||||
* Returns the waypoint collection for this world.
|
||||
*
|
||||
* @return The waypoint collection for this world
|
||||
*/
|
||||
IWaypointCollection getWaypoints();
|
||||
|
||||
/**
|
||||
* @return The {@link IContainerMemory} instance
|
||||
* @see IContainerMemory
|
||||
*/
|
||||
IContainerMemory getContainerMemory();
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package baritone.api.cache;
|
|||
import baritone.api.utils.IPlayerContext;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
@ -42,4 +43,18 @@ public interface IWorldScanner {
|
|||
* @return The matching block positions
|
||||
*/
|
||||
List<BlockPos> scanChunkRadius(IPlayerContext ctx, List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius);
|
||||
|
||||
/**
|
||||
* Scans a single chunk for the specified blocks.
|
||||
*
|
||||
* @param ctx The {@link IPlayerContext} containing player and world info that the
|
||||
* scan is based upon
|
||||
* @param blocks The blocks to scan for
|
||||
* @param pos The position of the target chunk
|
||||
* @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.
|
||||
* @return The matching block positions
|
||||
*/
|
||||
List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold);
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ package baritone.api.event.events;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
/**
|
||||
* Called when the local player interacts with a block, can be either {@link Type#BREAK} or {@link Type#USE}.
|
||||
* Called when the local player interacts with a block, can be either {@link Type#START_BREAK} or {@link Type#USE}.
|
||||
*
|
||||
* @author Brady
|
||||
* @since 8/22/2018
|
||||
|
@ -59,9 +59,9 @@ public final class BlockInteractEvent {
|
|||
public enum Type {
|
||||
|
||||
/**
|
||||
* We're breaking the target block.
|
||||
* We're starting to break the target block.
|
||||
*/
|
||||
BREAK,
|
||||
START_BREAK,
|
||||
|
||||
/**
|
||||
* We're right clicking on the target block. Either placing or interacting with.
|
||||
|
|
|
@ -31,7 +31,9 @@ public final class ChunkEvent {
|
|||
private final EventState state;
|
||||
|
||||
/**
|
||||
* The type of chunk event that occurred;
|
||||
* The type of chunk event that occurred
|
||||
*
|
||||
* @see Type
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
|
|
|
@ -36,9 +36,6 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
|||
@Override
|
||||
default void onPlayerUpdate(PlayerUpdateEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onProcessKeyBinds() {}
|
||||
|
||||
@Override
|
||||
default void onSendChatMessage(ChatEvent event) {}
|
||||
|
||||
|
|
|
@ -23,13 +23,9 @@ 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;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityLivingBase;
|
||||
import net.minecraft.network.NetworkManager;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.util.text.ITextComponent;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
|
@ -40,6 +36,7 @@ public interface IGameEventListener {
|
|||
/**
|
||||
* Run once per game tick before screen input is handled.
|
||||
*
|
||||
* @param event The event
|
||||
* @see Minecraft#runTick()
|
||||
*/
|
||||
void onTick(TickEvent event);
|
||||
|
@ -47,20 +44,15 @@ public interface IGameEventListener {
|
|||
/**
|
||||
* Run once per game tick from before and after the player rotation is sent to the server.
|
||||
*
|
||||
* @param event The event
|
||||
* @see EntityPlayerSP#onUpdate()
|
||||
*/
|
||||
void onPlayerUpdate(PlayerUpdateEvent event);
|
||||
|
||||
/**
|
||||
* Run once per game tick from before keybinds are processed.
|
||||
*
|
||||
* @see Minecraft#processKeyBinds()
|
||||
*/
|
||||
void onProcessKeyBinds();
|
||||
|
||||
/**
|
||||
* Runs whenever the client player sends a message to the server.
|
||||
*
|
||||
* @param event The event
|
||||
* @see EntityPlayerSP#sendChatMessage(String)
|
||||
*/
|
||||
void onSendChatMessage(ChatEvent event);
|
||||
|
@ -68,6 +60,7 @@ public interface IGameEventListener {
|
|||
/**
|
||||
* Runs before and after whenever a chunk is either loaded, unloaded, or populated.
|
||||
*
|
||||
* @param event The event
|
||||
* @see WorldClient#doPreChunk(int, int, boolean)
|
||||
*/
|
||||
void onChunkEvent(ChunkEvent event);
|
||||
|
@ -77,13 +70,14 @@ public interface IGameEventListener {
|
|||
* <p>
|
||||
* <b>Note:</b> {@link GameSettings#anaglyph} has been removed in Minecraft 1.13
|
||||
*
|
||||
* @see EntityRenderer#renderWorldPass(int, float, long)
|
||||
* @param event The event
|
||||
*/
|
||||
void onRenderPass(RenderEvent event);
|
||||
|
||||
/**
|
||||
* Runs before and after whenever a new world is loaded
|
||||
*
|
||||
* @param event The event
|
||||
* @see Minecraft#loadWorld(WorldClient, String)
|
||||
*/
|
||||
void onWorldEvent(WorldEvent event);
|
||||
|
@ -91,7 +85,7 @@ public interface IGameEventListener {
|
|||
/**
|
||||
* Runs before a outbound packet is sent
|
||||
*
|
||||
* @see NetworkManager#dispatchPacket(Packet, GenericFutureListener[])
|
||||
* @param event The event
|
||||
* @see Packet
|
||||
* @see GenericFutureListener
|
||||
*/
|
||||
|
@ -100,7 +94,7 @@ public interface IGameEventListener {
|
|||
/**
|
||||
* Runs before an inbound packet is processed
|
||||
*
|
||||
* @see NetworkManager#dispatchPacket(Packet, GenericFutureListener[])
|
||||
* @param event The event
|
||||
* @see Packet
|
||||
* @see GenericFutureListener
|
||||
*/
|
||||
|
@ -110,31 +104,29 @@ public interface IGameEventListener {
|
|||
* Run once per game tick from before and after the player's moveRelative method is called
|
||||
* and before and after the player jumps.
|
||||
*
|
||||
* @param event The event
|
||||
* @see Entity#moveRelative(float, float, float, float)
|
||||
* @see EntityLivingBase#jump()
|
||||
*/
|
||||
void onPlayerRotationMove(RotationMoveEvent event);
|
||||
|
||||
/**
|
||||
* Called when the local player interacts with a block, whether it is breaking or opening/placing.
|
||||
*
|
||||
* @see Minecraft#clickMouse()
|
||||
* @see Minecraft#rightClickMouse()
|
||||
* @param event The event
|
||||
*/
|
||||
void onBlockInteract(BlockInteractEvent event);
|
||||
|
||||
/**
|
||||
* Called when the local player dies, as indicated by the creation of the {@link GuiGameOver} screen.
|
||||
*
|
||||
* @see GuiGameOver(ITextComponent)
|
||||
* @see ITextComponent
|
||||
* @see GuiGameOver
|
||||
*/
|
||||
void onPlayerDeath();
|
||||
|
||||
/**
|
||||
* When the pathfinder's state changes
|
||||
*
|
||||
* @param event
|
||||
* @param event The event
|
||||
*/
|
||||
void onPathEvent(PathEvent event);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ import baritone.api.Settings;
|
|||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.movement.IMovement;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -52,6 +51,8 @@ public interface IPath {
|
|||
/**
|
||||
* This path is actually going to be executed in the world. Do whatever additional processing is required.
|
||||
* (as opposed to Path objects that are just constructed every frame for rendering)
|
||||
*
|
||||
* @return The result of path post processing
|
||||
*/
|
||||
default IPath postProcess() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
@ -109,8 +110,9 @@ public interface IPath {
|
|||
default double ticksRemainingFrom(int pathPosition) {
|
||||
double sum = 0;
|
||||
//this is fast because we aren't requesting recalculation, it's just cached
|
||||
for (int i = pathPosition; i < movements().size(); i++) {
|
||||
sum += movements().get(i).getCost();
|
||||
List<IMovement> movements = movements();
|
||||
for (int i = pathPosition; i < movements.size(); i++) {
|
||||
sum += movements.get(i).getCost();
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
@ -118,10 +120,13 @@ public interface IPath {
|
|||
/**
|
||||
* Cuts off this path at the loaded chunk border, and returns the resulting path. Default
|
||||
* implementation just returns this path, without the intended functionality.
|
||||
* <p>
|
||||
* The argument is supposed to be a BlockStateInterface LOL LOL LOL LOL LOL
|
||||
*
|
||||
* @param bsi The block state lookup, highly cursed
|
||||
* @return The result of this cut-off operation
|
||||
*/
|
||||
default IPath cutoffAtLoadedChunks(World world) {
|
||||
default IPath cutoffAtLoadedChunks(Object bsi) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
@ -129,6 +134,7 @@ public interface IPath {
|
|||
* Cuts off this path using the min length and cutoff factor settings, and returns the resulting path.
|
||||
* Default implementation just returns this path, without the intended functionality.
|
||||
*
|
||||
* @param destination The end goal of this path
|
||||
* @return The result of this cut-off operation
|
||||
* @see Settings#pathCutoffMinimumLength
|
||||
* @see Settings#pathCutoffFactor
|
||||
|
|
|
@ -34,6 +34,8 @@ public interface IPathFinder {
|
|||
/**
|
||||
* Calculate the path in full. Will take several seconds.
|
||||
*
|
||||
* @param primaryTimeout If a path is found, the path finder will stop after this amount of time
|
||||
* @param failureTimeout If a path isn't found, the path finder will continue for this amount of time
|
||||
* @return The final path
|
||||
*/
|
||||
PathCalculationResult calculate(long primaryTimeout, long failureTimeout);
|
||||
|
|
|
@ -30,6 +30,9 @@ public interface Goal {
|
|||
* Returns whether or not the specified position
|
||||
* meets the requirement for this goal based.
|
||||
*
|
||||
* @param x The goal X position
|
||||
* @param y The goal Y position
|
||||
* @param z The goal Z position
|
||||
* @return Whether or not it satisfies this goal
|
||||
*/
|
||||
boolean isInGoal(int x, int y, int z);
|
||||
|
@ -37,6 +40,9 @@ public interface Goal {
|
|||
/**
|
||||
* Estimate the number of ticks it will take to get to the goal
|
||||
*
|
||||
* @param x The goal X position
|
||||
* @param y The goal Y position
|
||||
* @param z The goal Z position
|
||||
* @return The estimate number of ticks to satisfy the goal
|
||||
*/
|
||||
double heuristic(int x, int y, int z);
|
||||
|
|
|
@ -20,8 +20,6 @@ package baritone.api.pathing.movement;
|
|||
import baritone.api.utils.BetterBlockPos;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 10/8/2018
|
||||
|
@ -58,10 +56,4 @@ public interface IMovement {
|
|||
BetterBlockPos getDest();
|
||||
|
||||
BlockPos getDirection();
|
||||
|
||||
List<BlockPos> toBreak();
|
||||
|
||||
List<BlockPos> toPlace();
|
||||
|
||||
List<BlockPos> toWalkInto();
|
||||
}
|
||||
|
|
|
@ -27,9 +27,7 @@ import net.minecraft.client.settings.KeyBinding;
|
|||
*/
|
||||
public interface IInputOverrideHandler extends IBehavior {
|
||||
|
||||
default boolean isInputForcedDown(KeyBinding key) {
|
||||
return isInputForcedDown(Input.getInputForBind(key));
|
||||
}
|
||||
Boolean isInputForcedDown(KeyBinding key);
|
||||
|
||||
boolean isInputForcedDown(Input input);
|
||||
|
||||
|
|
|
@ -20,7 +20,6 @@ package baritone.api.utils;
|
|||
import baritone.api.cache.IWorldData;
|
||||
import net.minecraft.block.BlockSlab;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.multiplayer.PlayerControllerMP;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
|
@ -37,7 +36,7 @@ public interface IPlayerContext {
|
|||
|
||||
EntityPlayerSP player();
|
||||
|
||||
PlayerControllerMP playerController();
|
||||
IPlayerController playerController();
|
||||
|
||||
World world();
|
||||
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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 net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.ClickType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.GameType;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 12/14/2018
|
||||
*/
|
||||
public interface IPlayerController {
|
||||
|
||||
boolean onPlayerDamageBlock(BlockPos pos, EnumFacing side);
|
||||
|
||||
void resetBlockRemoving();
|
||||
|
||||
ItemStack windowClick(int windowId, int slotId, int mouseButton, ClickType type, EntityPlayer player);
|
||||
|
||||
void setGameType(GameType type);
|
||||
|
||||
GameType getGameType();
|
||||
|
||||
default double getBlockReachDistance() {
|
||||
return this.getGameType().isCreative() ? 5.0F : 4.5F;
|
||||
}
|
||||
}
|
|
@ -19,6 +19,7 @@ package baritone.api.utils;
|
|||
|
||||
import baritone.api.pathing.calc.IPath;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PathCalculationResult {
|
||||
|
@ -31,11 +32,9 @@ public class PathCalculationResult {
|
|||
}
|
||||
|
||||
public PathCalculationResult(Type type, IPath path) {
|
||||
Objects.requireNonNull(type);
|
||||
this.path = path;
|
||||
this.type = type;
|
||||
if (type == null) {
|
||||
throw new IllegalArgumentException("come on");
|
||||
}
|
||||
}
|
||||
|
||||
public final Optional<IPath> getPath() {
|
||||
|
|
|
@ -34,7 +34,9 @@ public final class RayTraceUtils {
|
|||
* any entity collisions can be ignored, because this method will not recognize if an
|
||||
* entity is in the way or not. The local player's block reach distance will be used.
|
||||
*
|
||||
* @param entity The entity representing the raytrace source
|
||||
* @param rotation The rotation to raytrace towards
|
||||
* @param blockReachDistance The block reach distance of the entity
|
||||
* @return The calculated raytrace result
|
||||
*/
|
||||
public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance) {
|
||||
|
|
|
@ -110,6 +110,17 @@ public class Rotation {
|
|||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is really close to
|
||||
*
|
||||
* @param other another rotation
|
||||
* @return are they really close
|
||||
*/
|
||||
public boolean isReallyCloseTo(Rotation other) {
|
||||
float yawDiff = Math.abs(this.yaw - other.yaw); // you cant fool me
|
||||
return (yawDiff < 0.01 || yawDiff > 359.9) && Math.abs(this.pitch - other.pitch) < 0.01;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clamps the specified pitch value between -90 and 90.
|
||||
*
|
||||
|
@ -131,7 +142,7 @@ public class Rotation {
|
|||
if (newYaw < -180F) {
|
||||
newYaw += 360F;
|
||||
}
|
||||
if (newYaw >= 180F) {
|
||||
if (newYaw > 180F) {
|
||||
newYaw -= 360F;
|
||||
}
|
||||
return newYaw;
|
||||
|
|
|
@ -127,6 +127,16 @@ public final class RotationUtils {
|
|||
return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ctx Context for the viewing entity
|
||||
* @param pos The target block position
|
||||
* @return The optional rotation
|
||||
* @see #reachable(EntityPlayerSP, BlockPos, double)
|
||||
*/
|
||||
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos) {
|
||||
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified entity is able to reach the center of any of the sides
|
||||
* of the specified block. It first checks if the block center is reachable, and if so,
|
||||
|
@ -136,6 +146,7 @@ public final class RotationUtils {
|
|||
*
|
||||
* @param entity The viewing entity
|
||||
* @param pos The target block position
|
||||
* @param blockReachDistance The block reach distance of the entity
|
||||
* @return The optional rotation
|
||||
*/
|
||||
public static Optional<Rotation> reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance) {
|
||||
|
@ -181,6 +192,7 @@ public final class RotationUtils {
|
|||
* @param entity The viewing entity
|
||||
* @param pos The target block position
|
||||
* @param offsetPos The position of the block with the offset applied.
|
||||
* @param blockReachDistance The block reach distance of the entity
|
||||
* @return The optional rotation
|
||||
*/
|
||||
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) {
|
||||
|
@ -204,6 +216,7 @@ public final class RotationUtils {
|
|||
*
|
||||
* @param entity The viewing entity
|
||||
* @param pos The target block position
|
||||
* @param blockReachDistance The block reach distance of the entity
|
||||
* @return The optional rotation
|
||||
*/
|
||||
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) {
|
||||
|
|
|
@ -18,56 +18,77 @@
|
|||
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.io.BufferedReader;
|
||||
import java.io.BufferedWriter;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static net.minecraft.client.Minecraft.getMinecraft;
|
||||
|
||||
public class SettingsUtil {
|
||||
|
||||
private static final File settingsFile = new File(new File(Minecraft.getMinecraft().gameDir, "baritone"), "settings.txt");
|
||||
private static final Path SETTINGS_PATH = getMinecraft().gameDir.toPath().resolve("baritone").resolve("settings.txt");
|
||||
private static final Pattern SETTING_PATTERN = Pattern.compile("^(?<setting>[^ ]+) +(?<value>[^ ]+)"); // 2 words separated by spaces
|
||||
|
||||
private static final Map<Class<?>, SettingsIO> map;
|
||||
|
||||
private static boolean isComment(String line) {
|
||||
return line.startsWith("#") || line.startsWith("//");
|
||||
}
|
||||
|
||||
private static void forEachLine(Path file, Consumer<String> consumer) throws IOException {
|
||||
try (BufferedReader scan = Files.newBufferedReader(file)) {
|
||||
String line;
|
||||
while ((line = scan.readLine()) != null) {
|
||||
if (line.isEmpty() || isComment(line)) {
|
||||
continue;
|
||||
}
|
||||
consumer.accept(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void readAndApply(Settings settings) {
|
||||
try (Scanner scan = new Scanner(settingsFile)) {
|
||||
while (scan.hasNextLine()) {
|
||||
String line = scan.nextLine();
|
||||
if (line.isEmpty()) {
|
||||
continue;
|
||||
try {
|
||||
forEachLine(SETTINGS_PATH, line -> {
|
||||
Matcher matcher = SETTING_PATTERN.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
System.out.println("Invalid syntax in setting file: " + line);
|
||||
return;
|
||||
}
|
||||
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();
|
||||
|
||||
String settingName = matcher.group("setting").toLowerCase();
|
||||
String settingValue = matcher.group("value");
|
||||
try {
|
||||
parseAndApply(settings, settingName, settingValue);
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
System.out.println("Unable to parse line " + line);
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void save(Settings settings) {
|
||||
try (FileOutputStream out = new FileOutputStream(settingsFile)) {
|
||||
try (BufferedWriter out = Files.newBufferedWriter(SETTINGS_PATH)) {
|
||||
for (Settings.Setting setting : settings.allSettings) {
|
||||
if (setting.get() == null) {
|
||||
System.out.println("NULL SETTING?" + setting.getName());
|
||||
|
@ -83,11 +104,11 @@ public class SettingsUtil {
|
|||
if (io == null) {
|
||||
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName());
|
||||
}
|
||||
out.write((setting.getName() + " " + io.toString.apply(setting.get()) + "\n").getBytes());
|
||||
out.write(setting.getName() + " " + io.toString.apply(setting.get()) + "\n");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Exception thrown while saving Baritone settings!");
|
||||
ex.printStackTrace();
|
||||
System.out.println("Exception while saving Baritone settings!");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ public final class VecUtils {
|
|||
/**
|
||||
* Calculates the center of the block at the specified position's bounding box
|
||||
*
|
||||
* @param world The world that the block is in, used to provide the bounding box
|
||||
* @param pos The block position
|
||||
* @return The center of the block's bounding box
|
||||
* @see #getBlockPosCenter(BlockPos)
|
||||
|
@ -81,10 +82,9 @@ public final class VecUtils {
|
|||
* @see #getBlockPosCenter(BlockPos)
|
||||
*/
|
||||
public static double distanceToCenter(BlockPos pos, double x, double y, double z) {
|
||||
Vec3d center = getBlockPosCenter(pos);
|
||||
double xdiff = x - center.x;
|
||||
double ydiff = y - center.y;
|
||||
double zdiff = z - center.z;
|
||||
double xdiff = pos.getX() + 0.5 - x;
|
||||
double ydiff = pos.getY() + 0.5 - y;
|
||||
double zdiff = pos.getZ() + 0.5 - z;
|
||||
return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
|
||||
}
|
||||
|
||||
|
|
|
@ -18,8 +18,10 @@
|
|||
package baritone.launch.mixins;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.utils.Helper;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
@ -31,6 +33,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|||
@Mixin(KeyBinding.class)
|
||||
public class MixinKeyBinding {
|
||||
|
||||
@Shadow
|
||||
public int pressTime;
|
||||
|
||||
@Inject(
|
||||
method = "isKeyDown",
|
||||
at = @At("HEAD"),
|
||||
|
@ -38,8 +43,26 @@ public class MixinKeyBinding {
|
|||
)
|
||||
private void isKeyDown(CallbackInfoReturnable<Boolean> cir) {
|
||||
// only the primary baritone forces keys
|
||||
if (BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this)) {
|
||||
cir.setReturnValue(true);
|
||||
Boolean force = BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this);
|
||||
if (force != null) {
|
||||
cir.setReturnValue(force); // :sunglasses:
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "isPressed",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void isPressed(CallbackInfoReturnable<Boolean> cir) {
|
||||
// only the primary baritone forces keys
|
||||
Boolean force = BaritoneAPI.getProvider().getPrimaryBaritone().getInputOverrideHandler().isInputForcedDown((KeyBinding) (Object) this);
|
||||
if (force != null && force == false) { // <-- cursed
|
||||
if (pressTime > 0) {
|
||||
Helper.HELPER.logDirect("You're trying to press this mouse button but I won't let you");
|
||||
pressTime--;
|
||||
}
|
||||
cir.setReturnValue(force); // :sunglasses:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,15 +96,6 @@ public class MixinMinecraft {
|
|||
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "processKeyBinds",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void runTickKeyboard(CallbackInfo ci) {
|
||||
// keyboard input is only the primary baritone
|
||||
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onProcessKeyBinds();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "loadWorld(Lnet/minecraft/client/multiplayer/WorldClient;Ljava/lang/String;)V",
|
||||
at = @At("HEAD")
|
||||
|
@ -164,7 +155,7 @@ public class MixinMinecraft {
|
|||
)
|
||||
private void onBlockBreak(CallbackInfo ci, BlockPos pos) {
|
||||
// clickMouse is only for the main player
|
||||
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.BREAK));
|
||||
BaritoneAPI.getProvider().getPrimaryBaritone().getGameEventHandler().onBlockInteract(new BlockInteractEvent(pos, BlockInteractEvent.Type.START_BREAK));
|
||||
}
|
||||
|
||||
@Inject(
|
||||
|
|
|
@ -22,10 +22,7 @@ import baritone.api.IBaritone;
|
|||
import baritone.api.Settings;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.behavior.Behavior;
|
||||
import baritone.behavior.LookBehavior;
|
||||
import baritone.behavior.MemoryBehavior;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
import baritone.event.GameEventHandler;
|
||||
import baritone.process.CustomGoalProcess;
|
||||
|
@ -110,6 +107,7 @@ public class Baritone implements IBaritone {
|
|||
pathingBehavior = new PathingBehavior(this);
|
||||
lookBehavior = new LookBehavior(this);
|
||||
memoryBehavior = new MemoryBehavior(this);
|
||||
new InventoryBehavior(this);
|
||||
inputOverrideHandler = new InputOverrideHandler(this);
|
||||
new ExampleBaritoneControl(this);
|
||||
}
|
||||
|
@ -131,6 +129,7 @@ public class Baritone implements IBaritone {
|
|||
this.initialized = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingControlManager getPathingControlManager() {
|
||||
return this.pathingControlManager;
|
||||
}
|
||||
|
@ -164,6 +163,10 @@ public class Baritone implements IBaritone {
|
|||
return this.playerContext;
|
||||
}
|
||||
|
||||
public MemoryBehavior getMemoryBehavior() {
|
||||
return this.memoryBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FollowProcess getFollowProcess() {
|
||||
return this.followProcess;
|
||||
|
@ -174,11 +177,6 @@ public class Baritone implements IBaritone {
|
|||
return this.lookBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MemoryBehavior getMemoryBehavior() {
|
||||
return this.memoryBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MineProcess getMineProcess() {
|
||||
return this.mineProcess;
|
||||
|
|
|
@ -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 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.behavior;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.utils.ToolSet;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.inventory.ClickType;
|
||||
import net.minecraft.item.ItemPickaxe;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.item.ItemTool;
|
||||
import net.minecraft.util.NonNullList;
|
||||
|
||||
public class InventoryBehavior extends Behavior {
|
||||
public InventoryBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(TickEvent event) {
|
||||
if (!Baritone.settings().allowInventory.get()) {
|
||||
return;
|
||||
}
|
||||
if (event.getType() == TickEvent.Type.OUT) {
|
||||
return;
|
||||
}
|
||||
if (ctx.player().openContainer != ctx.player().inventoryContainer) {
|
||||
// we have a crafting table or a chest or something open
|
||||
return;
|
||||
}
|
||||
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
|
||||
swapWithHotBar(firstValidThrowaway(), 8);
|
||||
}
|
||||
int pick = bestToolAgainst(Blocks.STONE, ItemPickaxe.class);
|
||||
if (pick >= 9) {
|
||||
swapWithHotBar(pick, 0);
|
||||
}
|
||||
}
|
||||
|
||||
private void swapWithHotBar(int inInventory, int inHotbar) {
|
||||
ctx.playerController().windowClick(ctx.player().inventoryContainer.windowId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player());
|
||||
}
|
||||
|
||||
private int firstValidThrowaway() { // TODO offhand idk
|
||||
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
|
||||
for (int i = 0; i < invy.size(); i++) {
|
||||
if (Baritone.settings().acceptableThrowawayItems.get().contains(invy.get(i).getItem())) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int bestToolAgainst(Block against, Class<? extends ItemTool> klass) {
|
||||
NonNullList<ItemStack> invy = ctx.player().inventory.mainInventory;
|
||||
int bestInd = -1;
|
||||
double bestSpeed = -1;
|
||||
for (int i = 0; i < invy.size(); i++) {
|
||||
ItemStack stack = invy.get(i);
|
||||
if (stack.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if (klass.isInstance(stack.getItem())) {
|
||||
double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants
|
||||
if (speed > bestSpeed) {
|
||||
bestSpeed = speed;
|
||||
bestInd = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bestInd;
|
||||
}
|
||||
}
|
|
@ -18,16 +18,18 @@
|
|||
package baritone.behavior;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.behavior.IMemoryBehavior;
|
||||
import baritone.api.behavior.memory.IRememberedInventory;
|
||||
import baritone.api.cache.IWorldData;
|
||||
import baritone.api.event.events.BlockInteractEvent;
|
||||
import baritone.api.event.events.PacketEvent;
|
||||
import baritone.api.event.events.PlayerUpdateEvent;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.cache.ContainerMemory;
|
||||
import baritone.cache.Waypoint;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockBed;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.Packet;
|
||||
import net.minecraft.network.play.client.CPacketCloseWindow;
|
||||
|
@ -36,22 +38,37 @@ import net.minecraft.network.play.server.SPacketCloseWindow;
|
|||
import net.minecraft.network.play.server.SPacketOpenWindow;
|
||||
import net.minecraft.tileentity.TileEntity;
|
||||
import net.minecraft.tileentity.TileEntityLockable;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.text.TextComponentTranslation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/6/2018
|
||||
*/
|
||||
public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
|
||||
public final class MemoryBehavior extends Behavior {
|
||||
|
||||
private final Map<IWorldData, WorldDataContainer> worldDataContainers = new HashMap<>();
|
||||
private final List<FutureInventory> futureInventories = new ArrayList<>(); // this is per-bot
|
||||
|
||||
private Integer enderChestWindowId; // nae nae
|
||||
|
||||
public MemoryBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onTick(TickEvent event) {
|
||||
if (event.getType() == TickEvent.Type.OUT) {
|
||||
enderChestWindowId = null;
|
||||
futureInventories.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void onPlayerUpdate(PlayerUpdateEvent event) {
|
||||
if (event.getState() == EventState.PRE) {
|
||||
|
@ -68,19 +85,30 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
|
|||
CPacketPlayerTryUseItemOnBlock packet = event.cast();
|
||||
|
||||
TileEntity tileEntity = ctx.world().getTileEntity(packet.getPos());
|
||||
// if tileEntity is an ender chest, we don't need to do anything. ender chests are treated the same regardless of what coordinate right clicked
|
||||
|
||||
// Ensure the TileEntity is a container of some sort
|
||||
if (tileEntity instanceof TileEntityLockable) {
|
||||
|
||||
TileEntityLockable lockable = (TileEntityLockable) tileEntity;
|
||||
int size = lockable.getSizeInventory();
|
||||
BlockPos position = tileEntity.getPos();
|
||||
BlockPos adj = neighboringConnectedBlock(position);
|
||||
System.out.println(position + " " + adj);
|
||||
if (adj != null) {
|
||||
size *= 2; // double chest or double trapped chest
|
||||
if (adj.getX() < position.getX() || adj.getZ() < position.getZ()) {
|
||||
position = adj; // standardize on the lower coordinate, regardless of which side of the large chest we right clicked
|
||||
}
|
||||
}
|
||||
|
||||
this.getCurrentContainer().futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), tileEntity.getPos()));
|
||||
this.futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), position));
|
||||
}
|
||||
}
|
||||
|
||||
if (p instanceof CPacketCloseWindow) {
|
||||
updateInventory();
|
||||
getCurrent().save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -92,27 +120,30 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
|
|||
if (event.getState() == EventState.PRE) {
|
||||
if (p instanceof SPacketOpenWindow) {
|
||||
SPacketOpenWindow packet = event.cast();
|
||||
|
||||
WorldDataContainer container = this.getCurrentContainer();
|
||||
|
||||
// Remove any entries that were created over a second ago, this should make up for INSANE latency
|
||||
container.futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
|
||||
futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
|
||||
|
||||
container.futureInventories.stream()
|
||||
System.out.println("Received packet " + packet.getGuiId() + " " + packet.getEntityId() + " " + packet.getSlotCount() + " " + packet.getWindowId());
|
||||
System.out.println(packet.getWindowTitle());
|
||||
if (packet.getWindowTitle() instanceof TextComponentTranslation && ((TextComponentTranslation) packet.getWindowTitle()).getKey().equals("container.enderchest")) {
|
||||
// title is not customized (i.e. this isn't just a renamed shulker)
|
||||
enderChestWindowId = packet.getWindowId();
|
||||
return;
|
||||
}
|
||||
futureInventories.stream()
|
||||
.filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount())
|
||||
.findFirst().ifPresent(matched -> {
|
||||
// Remove the future inventory
|
||||
container.futureInventories.remove(matched);
|
||||
futureInventories.remove(matched);
|
||||
|
||||
// Setup the remembered inventory
|
||||
RememberedInventory inventory = container.rememberedInventories.computeIfAbsent(matched.pos, pos -> new RememberedInventory());
|
||||
inventory.windowId = packet.getWindowId();
|
||||
inventory.size = packet.getSlotCount();
|
||||
getCurrentContainer().setup(matched.pos, packet.getWindowId(), packet.getSlotCount());
|
||||
});
|
||||
}
|
||||
|
||||
if (p instanceof SPacketCloseWindow) {
|
||||
updateInventory();
|
||||
getCurrent().save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -129,43 +160,42 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
|
|||
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet()));
|
||||
}
|
||||
|
||||
private Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
|
||||
return this.getCurrentContainer().rememberedInventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
|
||||
}
|
||||
|
||||
private void updateInventory() {
|
||||
getInventoryFromWindow(ctx.player().openContainer.windowId).ifPresent(inventory -> {
|
||||
inventory.items.clear();
|
||||
inventory.items.addAll(ctx.player().openContainer.getInventory().subList(0, inventory.size));
|
||||
});
|
||||
int windowId = ctx.player().openContainer.windowId;
|
||||
if (enderChestWindowId != null) {
|
||||
if (windowId == enderChestWindowId) {
|
||||
getCurrent().contents = ctx.player().openContainer.getInventory().subList(0, 27);
|
||||
} else {
|
||||
getCurrent().save();
|
||||
enderChestWindowId = null;
|
||||
}
|
||||
}
|
||||
if (getCurrentContainer() != null) {
|
||||
getCurrentContainer().getInventoryFromWindow(windowId).ifPresent(inventory -> inventory.updateFromOpenWindow(ctx));
|
||||
}
|
||||
}
|
||||
|
||||
private WorldDataContainer getCurrentContainer() {
|
||||
return this.worldDataContainers.computeIfAbsent(baritone.getWorldProvider().getCurrentWorld(), data -> new WorldDataContainer());
|
||||
private ContainerMemory getCurrentContainer() {
|
||||
if (baritone.getWorldProvider().getCurrentWorld() == null) {
|
||||
return null;
|
||||
}
|
||||
return (ContainerMemory) baritone.getWorldProvider().getCurrentWorld().getContainerMemory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
|
||||
return this.getCurrentContainer().rememberedInventories.get(pos);
|
||||
private BlockPos neighboringConnectedBlock(BlockPos in) {
|
||||
BlockStateInterface bsi = new CalculationContext(baritone).bsi;
|
||||
Block block = bsi.get0(in).getBlock();
|
||||
if (block != Blocks.TRAPPED_CHEST && block != Blocks.CHEST) {
|
||||
return null; // other things that have contents, but can be placed adjacent without combining
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos adj = in.offset(EnumFacing.byHorizontalIndex(i));
|
||||
if (bsi.get0(adj).getBlock() == block) {
|
||||
return adj;
|
||||
}
|
||||
|
||||
private static final class WorldDataContainer {
|
||||
|
||||
/**
|
||||
* Possible future inventories that we will be able to remember
|
||||
*/
|
||||
private final List<FutureInventory> futureInventories = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The current remembered inventories
|
||||
*/
|
||||
private final Map<BlockPos, RememberedInventory> rememberedInventories = new HashMap<>();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,43 +228,51 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior {
|
|||
this.slots = slots;
|
||||
this.type = type;
|
||||
this.pos = pos;
|
||||
System.out.println("Future inventory created " + time + " " + slots + " " + type + " " + pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An inventory that we are aware of.
|
||||
* <p>
|
||||
* Associated with a {@link BlockPos} in {@link WorldDataContainer#rememberedInventories}.
|
||||
*/
|
||||
public static class RememberedInventory implements IRememberedInventory {
|
||||
|
||||
/**
|
||||
* The list of items in the inventory
|
||||
*/
|
||||
private final List<ItemStack> items;
|
||||
|
||||
/**
|
||||
* The last known window ID of the inventory
|
||||
*/
|
||||
private int windowId;
|
||||
|
||||
/**
|
||||
* The size of the inventory
|
||||
*/
|
||||
private int size;
|
||||
|
||||
private RememberedInventory() {
|
||||
this.items = new ArrayList<>();
|
||||
public Optional<List<ItemStack>> echest() {
|
||||
return Optional.ofNullable(getCurrent().contents).map(Collections::unmodifiableList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<ItemStack> getContents() {
|
||||
return Collections.unmodifiableList(this.items);
|
||||
public EnderChestMemory getCurrent() {
|
||||
Path path = baritone.getWorldProvider().getCurrentWorld().directory;
|
||||
return EnderChestMemory.getByServerAndPlayer(path.getParent(), ctx.player().getUniqueID());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getSize() {
|
||||
return this.size;
|
||||
public static class EnderChestMemory {
|
||||
private static final Map<Path, EnderChestMemory> memory = new HashMap<>();
|
||||
private final Path enderChest;
|
||||
private List<ItemStack> contents;
|
||||
|
||||
private EnderChestMemory(Path enderChest) {
|
||||
this.enderChest = enderChest;
|
||||
System.out.println("Echest storing in " + enderChest);
|
||||
try {
|
||||
this.contents = ContainerMemory.readItemStacks(Files.readAllBytes(enderChest));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("CANNOT read echest =( =(");
|
||||
this.contents = null;
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void save() {
|
||||
System.out.println("Saving");
|
||||
if (contents != null) {
|
||||
try {
|
||||
enderChest.getParent().toFile().mkdir();
|
||||
Files.write(enderChest, ContainerMemory.writeItemStacks(contents));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("CANNOT save echest =( =(");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static synchronized EnderChestMemory getByServerAndPlayer(Path serverStorage, UUID player) {
|
||||
return memory.computeIfAbsent(serverStorage.resolve("echests").resolve(player.toString()), EnderChestMemory::new);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,12 +37,15 @@ import baritone.pathing.path.CutoffPath;
|
|||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.utils.Helper;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper {
|
||||
|
||||
|
@ -277,11 +280,13 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
}
|
||||
|
||||
public void softCancelIfSafe() {
|
||||
synchronized (pathPlanLock) {
|
||||
if (!isSafeToCancel()) {
|
||||
return;
|
||||
}
|
||||
current = null;
|
||||
next = null;
|
||||
}
|
||||
cancelRequested = true;
|
||||
getInProgress().ifPresent(AbstractNodeCostSearch::cancel); // only cancel ours
|
||||
// do everything BUT clear keys
|
||||
|
@ -290,8 +295,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
// just cancel the current path
|
||||
public void secretInternalSegmentCancel() {
|
||||
queuePathEvent(PathEvent.CANCELED);
|
||||
synchronized (pathPlanLock) {
|
||||
current = null;
|
||||
next = null;
|
||||
}
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
getInProgress().ifPresent(AbstractNodeCostSearch::cancel);
|
||||
baritone.getInputOverrideHandler().getBlockBreakHelper().stopBreakingBlock();
|
||||
|
@ -330,12 +337,18 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
}
|
||||
}
|
||||
|
||||
public void secretCursedFunctionDoNotCall(IPath path) {
|
||||
synchronized (pathPlanLock) {
|
||||
current = new PathExecutor(this, path);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* See issue #209
|
||||
*
|
||||
* @return The starting {@link BlockPos} for a new path
|
||||
*/
|
||||
public BlockPos pathStart() { // TODO move to a helper or util class
|
||||
public BetterBlockPos pathStart() { // TODO move to a helper or util class
|
||||
BetterBlockPos feet = ctx.playerFeet();
|
||||
if (!MovementHelper.canWalkOn(ctx, feet.down())) {
|
||||
if (ctx.player().onGround) {
|
||||
|
@ -405,9 +418,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
primaryTimeout = Baritone.settings().planAheadPrimaryTimeoutMS.get();
|
||||
failureTimeout = Baritone.settings().planAheadFailureTimeoutMS.get();
|
||||
}
|
||||
CalculationContext context = new CalculationContext(baritone); // not safe to create on the other thread, it looks up a lot of stuff in minecraft
|
||||
CalculationContext context = new CalculationContext(baritone, true); // not safe to create on the other thread, it looks up a lot of stuff in minecraft
|
||||
AbstractNodeCostSearch pathfinder = createPathfinder(start, goal, current == null ? null : current.getPath(), context);
|
||||
if (!Objects.equals(pathfinder.getGoal(), goal)) {
|
||||
if (!Objects.equals(pathfinder.getGoal(), goal)) { // will return the exact same object if simplification didn't happen
|
||||
logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance");
|
||||
}
|
||||
inProgress = pathfinder;
|
||||
|
@ -420,7 +433,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
Optional<IPath> path = calcResult.getPath();
|
||||
if (Baritone.settings().cutoffAtLoadBoundary.get()) {
|
||||
path = path.map(p -> {
|
||||
IPath result = p.cutoffAtLoadedChunks(context.world());
|
||||
IPath result = p.cutoffAtLoadedChunks(context.bsi);
|
||||
|
||||
if (result instanceof CutoffPath) {
|
||||
logDebug("Cutting off path at edge of loaded chunks");
|
||||
|
@ -463,7 +476,9 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
queuePathEvent(PathEvent.NEXT_CALC_FAILED);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalStateException("I have no idea what to do with this path");
|
||||
//throw new IllegalStateException("I have no idea what to do with this path");
|
||||
// no point in throwing an exception here, and it gets it stuck with inProgress being not null
|
||||
logDirect("Warning: PathingBehaivor illegal state! Discarding invalid path!");
|
||||
}
|
||||
}
|
||||
if (talkAboutIt && current != null && current.getPath() != null) {
|
||||
|
@ -484,15 +499,12 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
|||
Goal transformed = goal;
|
||||
if (Baritone.settings().simplifyUnloadedYCoord.get() && goal instanceof IGoalRenderPos) {
|
||||
BlockPos pos = ((IGoalRenderPos) goal).getGoalPos();
|
||||
if (context.world().getChunk(pos) instanceof EmptyChunk) {
|
||||
if (!context.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ())) {
|
||||
transformed = new GoalXZ(pos.getX(), pos.getZ());
|
||||
}
|
||||
}
|
||||
HashSet<Long> favoredPositions = null;
|
||||
if (Baritone.settings().backtrackCostFavoringCoefficient.get() != 1D && previous != null) {
|
||||
favoredPositions = previous.positions().stream().map(BetterBlockPos::longHash).collect(Collectors.toCollection(HashSet::new));
|
||||
}
|
||||
return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoredPositions, context);
|
||||
Favoring favoring = new Favoring(context.getBaritone().getPlayerContext(), previous);
|
||||
return new AStarPathFinder(start.getX(), start.getY(), start.getZ(), transformed, favoring, context);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,7 +35,7 @@ public final class CachedChunk {
|
|||
|
||||
static {
|
||||
HashSet<Block> temp = new HashSet<>();
|
||||
temp.add(Blocks.DIAMOND_ORE);
|
||||
//temp.add(Blocks.DIAMOND_ORE);
|
||||
temp.add(Blocks.DIAMOND_BLOCK);
|
||||
//temp.add(Blocks.COAL_ORE);
|
||||
temp.add(Blocks.COAL_BLOCK);
|
||||
|
|
|
@ -179,8 +179,8 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
|||
if (region == null) {
|
||||
continue;
|
||||
}
|
||||
int distX = (region.getX() * 512 + 256) - pruneCenter.getX();
|
||||
int distZ = (region.getZ() * 512 + 256) - pruneCenter.getZ();
|
||||
int distX = (region.getX() << 9 + 256) - pruneCenter.getX();
|
||||
int distZ = (region.getZ() << 9 + 256) - pruneCenter.getZ();
|
||||
double dist = Math.sqrt(distX * distX + distZ * distZ);
|
||||
if (dist > 1024) {
|
||||
logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram");
|
||||
|
@ -215,7 +215,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
|||
if (mostRecentlyModified == null) {
|
||||
return new BlockPos(0, 0, 0);
|
||||
}
|
||||
return new BlockPos(mostRecentlyModified.x * 16 + 8, 0, mostRecentlyModified.z * 16 + 8);
|
||||
return new BlockPos(mostRecentlyModified.x << 4 + 8, 0, mostRecentlyModified.z << 4 + 8);
|
||||
}
|
||||
|
||||
private synchronized List<CachedRegion> allRegions() {
|
||||
|
@ -255,6 +255,10 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
|||
});
|
||||
}
|
||||
|
||||
public void tryLoadFromDisk(int regionX, int regionZ) {
|
||||
getOrCreateRegion(regionX, regionZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the region ID based on the region coordinates. 0 will be
|
||||
* returned if the specified region coordinates are out of bounds.
|
||||
|
|
|
@ -39,6 +39,8 @@ import java.util.*;
|
|||
*/
|
||||
public final class ChunkPacker {
|
||||
|
||||
private static final Map<String, Block> resourceCache = new HashMap<>();
|
||||
|
||||
private ChunkPacker() {}
|
||||
|
||||
public static CachedChunk pack(Chunk chunk) {
|
||||
|
@ -91,10 +93,7 @@ public final class ChunkPacker {
|
|||
IBlockState[] blocks = new IBlockState[256];
|
||||
|
||||
for (int z = 0; z < 16; z++) {
|
||||
// @formatter:off
|
||||
https:
|
||||
//www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html
|
||||
// @formatter:on
|
||||
https://www.ibm.com/developerworks/library/j-perry-writing-good-java-code/index.html
|
||||
for (int x = 0; x < 16; x++) {
|
||||
for (int y = 255; y >= 0; y--) {
|
||||
int index = CachedChunk.getPositionIndex(x, y, z);
|
||||
|
@ -120,7 +119,7 @@ public final class ChunkPacker {
|
|||
}
|
||||
|
||||
public static Block stringToBlock(String name) {
|
||||
return Block.getBlockFromName(name.contains(":") ? name : "minecraft:" + name);
|
||||
return resourceCache.computeIfAbsent(name, n -> Block.getBlockFromName(n.contains(":") ? n : "minecraft:" + n));
|
||||
}
|
||||
|
||||
private static PathingBlockType getPathingBlockType(IBlockState state) {
|
||||
|
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* 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.cache;
|
||||
|
||||
import baritone.api.cache.IContainerMemory;
|
||||
import baritone.api.cache.IRememberedInventory;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.network.PacketBuffer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class ContainerMemory implements IContainerMemory {
|
||||
|
||||
private final Path saveTo;
|
||||
/**
|
||||
* The current remembered inventories
|
||||
*/
|
||||
private final Map<BlockPos, RememberedInventory> inventories = new HashMap<>();
|
||||
|
||||
|
||||
public ContainerMemory(Path saveTo) {
|
||||
this.saveTo = saveTo;
|
||||
try {
|
||||
read(Files.readAllBytes(saveTo));
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
inventories.clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void read(byte[] bytes) throws IOException {
|
||||
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
|
||||
int chests = in.readInt();
|
||||
for (int i = 0; i < chests; i++) {
|
||||
int x = in.readInt();
|
||||
int y = in.readInt();
|
||||
int z = in.readInt();
|
||||
RememberedInventory rem = new RememberedInventory();
|
||||
rem.items.addAll(readItemStacks(in));
|
||||
rem.size = rem.items.size();
|
||||
rem.windowId = -1;
|
||||
if (rem.items.isEmpty()) {
|
||||
continue; // this only happens if the list has no elements, not if the list has elements that are all empty item stacks
|
||||
}
|
||||
inventories.put(new BlockPos(x, y, z), rem);
|
||||
}
|
||||
}
|
||||
|
||||
public synchronized void save() throws IOException {
|
||||
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
|
||||
PacketBuffer out = new PacketBuffer(buf);
|
||||
out.writeInt(inventories.size());
|
||||
for (Map.Entry<BlockPos, RememberedInventory> entry : inventories.entrySet()) {
|
||||
out = new PacketBuffer(out.writeInt(entry.getKey().getX()));
|
||||
out = new PacketBuffer(out.writeInt(entry.getKey().getY()));
|
||||
out = new PacketBuffer(out.writeInt(entry.getKey().getZ()));
|
||||
out = writeItemStacks(entry.getValue().getContents(), out);
|
||||
}
|
||||
Files.write(saveTo, out.array());
|
||||
}
|
||||
|
||||
public synchronized void setup(BlockPos pos, int windowId, int slotCount) {
|
||||
RememberedInventory inventory = inventories.computeIfAbsent(pos, x -> new RememberedInventory());
|
||||
inventory.windowId = windowId;
|
||||
inventory.size = slotCount;
|
||||
}
|
||||
|
||||
public synchronized Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
|
||||
return inventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized RememberedInventory getInventoryByPos(BlockPos pos) {
|
||||
return inventories.get(pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final synchronized Map<BlockPos, IRememberedInventory> getRememberedInventories() {
|
||||
// make a copy since this map is modified from the packet thread
|
||||
return new HashMap<>(inventories);
|
||||
}
|
||||
|
||||
public static List<ItemStack> readItemStacks(byte[] bytes) throws IOException {
|
||||
PacketBuffer in = new PacketBuffer(Unpooled.wrappedBuffer(bytes));
|
||||
return readItemStacks(in);
|
||||
}
|
||||
|
||||
public static List<ItemStack> readItemStacks(PacketBuffer in) throws IOException {
|
||||
int count = in.readInt();
|
||||
List<ItemStack> result = new ArrayList<>();
|
||||
for (int i = 0; i < count; i++) {
|
||||
result.add(in.readItemStack());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public static byte[] writeItemStacks(List<ItemStack> write) {
|
||||
ByteBuf buf = Unpooled.buffer(0, Integer.MAX_VALUE);
|
||||
PacketBuffer out = new PacketBuffer(buf);
|
||||
out = writeItemStacks(write, out);
|
||||
return out.array();
|
||||
}
|
||||
|
||||
public static PacketBuffer writeItemStacks(List<ItemStack> write, PacketBuffer out2) {
|
||||
PacketBuffer out = out2; // avoid reassigning an argument LOL
|
||||
out = new PacketBuffer(out.writeInt(write.size()));
|
||||
for (ItemStack stack : write) {
|
||||
out = out.writeItemStack(stack);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* An inventory that we are aware of.
|
||||
* <p>
|
||||
* Associated with a {@link BlockPos} in {@link ContainerMemory#inventories}.
|
||||
*/
|
||||
public static class RememberedInventory implements IRememberedInventory {
|
||||
|
||||
/**
|
||||
* The list of items in the inventory
|
||||
*/
|
||||
private final List<ItemStack> items;
|
||||
|
||||
/**
|
||||
* The last known window ID of the inventory
|
||||
*/
|
||||
private int windowId;
|
||||
|
||||
/**
|
||||
* The size of the inventory
|
||||
*/
|
||||
private int size;
|
||||
|
||||
private RememberedInventory() {
|
||||
this.items = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final List<ItemStack> getContents() {
|
||||
return Collections.unmodifiableList(this.items);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final int getSize() {
|
||||
return this.size;
|
||||
}
|
||||
|
||||
public void updateFromOpenWindow(IPlayerContext ctx) {
|
||||
items.clear();
|
||||
items.addAll(ctx.player().openContainer.getInventory().subList(0, size));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -32,7 +32,7 @@ import java.util.stream.Collectors;
|
|||
*
|
||||
* @author leijurv
|
||||
*/
|
||||
public class Waypoints implements IWaypointCollection {
|
||||
public class WaypointCollection implements IWaypointCollection {
|
||||
|
||||
/**
|
||||
* Magic value to detect invalid waypoint files
|
||||
|
@ -42,7 +42,7 @@ public class Waypoints implements IWaypointCollection {
|
|||
private final Path directory;
|
||||
private final Map<IWaypoint.Tag, Set<IWaypoint>> waypoints;
|
||||
|
||||
Waypoints(Path directory) {
|
||||
WaypointCollection(Path directory) {
|
||||
this.directory = directory;
|
||||
if (!Files.exists(directory)) {
|
||||
try {
|
|
@ -19,9 +19,11 @@ package baritone.cache;
|
|||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.cache.ICachedWorld;
|
||||
import baritone.api.cache.IContainerMemory;
|
||||
import baritone.api.cache.IWaypointCollection;
|
||||
import baritone.api.cache.IWorldData;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Path;
|
||||
|
||||
/**
|
||||
|
@ -32,7 +34,8 @@ import java.nio.file.Path;
|
|||
public class WorldData implements IWorldData {
|
||||
|
||||
public final CachedWorld cache;
|
||||
private final Waypoints waypoints;
|
||||
private final WaypointCollection waypoints;
|
||||
private final ContainerMemory containerMemory;
|
||||
//public final MapData map;
|
||||
public final Path directory;
|
||||
public final int dimension;
|
||||
|
@ -40,7 +43,8 @@ public class WorldData implements IWorldData {
|
|||
WorldData(Path directory, int dimension) {
|
||||
this.directory = directory;
|
||||
this.cache = new CachedWorld(directory.resolve("cache"), dimension);
|
||||
this.waypoints = new Waypoints(directory.resolve("waypoints"));
|
||||
this.waypoints = new WaypointCollection(directory.resolve("waypoints"));
|
||||
this.containerMemory = new ContainerMemory(directory.resolve("containers"));
|
||||
this.dimension = dimension;
|
||||
}
|
||||
|
||||
|
@ -49,6 +53,15 @@ public class WorldData implements IWorldData {
|
|||
System.out.println("Started saving the world in a new thread");
|
||||
cache.save();
|
||||
});
|
||||
Baritone.getExecutor().execute(() -> {
|
||||
System.out.println("Started saving saved containers in a new thread");
|
||||
try {
|
||||
containerMemory.save();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.out.println("Failed to save saved containers");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,4 +73,9 @@ public class WorldData implements IWorldData {
|
|||
public IWaypointCollection getWaypoints() {
|
||||
return this.waypoints;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContainerMemory getContainerMemory() {
|
||||
return this.containerMemory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,8 +95,10 @@ public class WorldProvider implements IWorldProvider, Helper {
|
|||
}
|
||||
|
||||
System.out.println("Baritone world data dir: " + dir);
|
||||
synchronized (worldCache) {
|
||||
this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, dimension));
|
||||
}
|
||||
}
|
||||
|
||||
public final void closeWorld() {
|
||||
WorldData world = this.currentWorld;
|
||||
|
|
|
@ -23,11 +23,14 @@ import net.minecraft.block.Block;
|
|||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.multiplayer.ChunkProviderClient;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.ChunkPos;
|
||||
import net.minecraft.world.chunk.BlockStateContainer;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public enum WorldScanner implements IWorldScanner {
|
||||
|
@ -39,7 +42,7 @@ public enum WorldScanner implements IWorldScanner {
|
|||
if (blocks.contains(null)) {
|
||||
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString());
|
||||
}
|
||||
LinkedList<BlockPos> res = new LinkedList<>();
|
||||
ArrayList<BlockPos> res = new ArrayList<>();
|
||||
if (blocks.isEmpty()) {
|
||||
return res;
|
||||
}
|
||||
|
@ -69,9 +72,40 @@ public enum WorldScanner implements IWorldScanner {
|
|||
continue;
|
||||
}
|
||||
allUnloaded = false;
|
||||
scanChunkInto(chunkX << 4, chunkZ << 4, chunk, blocks, res, max, yLevelThreshold, playerY);
|
||||
}
|
||||
}
|
||||
if ((allUnloaded && foundChunks)
|
||||
|| (res.size() >= max
|
||||
&& (searchRadiusSq > maxSearchRadiusSq || (searchRadiusSq > 1 && foundWithinY)))
|
||||
) {
|
||||
return res;
|
||||
}
|
||||
searchRadiusSq++;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> scanChunk(IPlayerContext ctx, List<Block> blocks, ChunkPos pos, int max, int yLevelThreshold) {
|
||||
if (blocks.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ChunkProviderClient chunkProvider = (ChunkProviderClient) ctx.world().getChunkProvider();
|
||||
Chunk chunk = chunkProvider.getLoadedChunk(pos.x, pos.z);
|
||||
int playerY = ctx.playerFeet().getY();
|
||||
|
||||
if (chunk == null || chunk.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
ArrayList<BlockPos> res = new ArrayList<>();
|
||||
scanChunkInto(pos.x << 4, pos.z << 4, chunk, blocks, res, max, yLevelThreshold, playerY);
|
||||
return res;
|
||||
}
|
||||
|
||||
public void scanChunkInto(int chunkX, int chunkZ, Chunk chunk, List<Block> search, Collection<BlockPos> result, int max, int yLevelThreshold, int playerY) {
|
||||
ExtendedBlockStorage[] chunkInternalStorageArray = chunk.getBlockStorageArray();
|
||||
chunkX = chunkX << 4;
|
||||
chunkZ = chunkZ << 4;
|
||||
for (int y0 = 0; y0 < 16; y0++) {
|
||||
ExtendedBlockStorage extendedblockstorage = chunkInternalStorageArray[y0];
|
||||
if (extendedblockstorage == null) {
|
||||
|
@ -85,11 +119,11 @@ public enum WorldScanner implements IWorldScanner {
|
|||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
IBlockState state = bsc.get(x, y, z);
|
||||
if (blocks.contains(state.getBlock())) {
|
||||
if (search.contains(state.getBlock())) {
|
||||
int yy = yReal | y;
|
||||
res.add(new BlockPos(chunkX | x, yy, chunkZ | z));
|
||||
if (Math.abs(yy - playerY) < yLevelThreshold) {
|
||||
foundWithinY = true;
|
||||
result.add(new BlockPos(chunkX | x, yy, chunkZ | z));
|
||||
if (result.size() >= max && Math.abs(yy - playerY) < yLevelThreshold) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,13 +132,3 @@ public enum WorldScanner implements IWorldScanner {
|
|||
}
|
||||
}
|
||||
}
|
||||
if ((allUnloaded && foundChunks)
|
||||
|| (res.size() >= max
|
||||
&& (searchRadiusSq > maxSearchRadiusSq || (searchRadiusSq > 1 && foundWithinY)))
|
||||
) {
|
||||
return res;
|
||||
}
|
||||
searchRadiusSq++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,11 +54,6 @@ public final class GameEventHandler implements IEventBus, Helper {
|
|||
listeners.forEach(l -> l.onPlayerUpdate(event));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onProcessKeyBinds() {
|
||||
listeners.forEach(IGameEventListener::onProcessKeyBinds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onSendChatMessage(ChatEvent event) {
|
||||
listeners.forEach(l -> l.onSendChatMessage(event));
|
||||
|
|
|
@ -28,10 +28,13 @@ import baritone.pathing.movement.Moves;
|
|||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.Helper;
|
||||
import baritone.utils.pathing.BetterWorldBorder;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
import baritone.utils.pathing.MutableMoveResult;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* The actual A* pathfinding
|
||||
|
@ -40,12 +43,12 @@ import java.util.*;
|
|||
*/
|
||||
public final class AStarPathFinder extends AbstractNodeCostSearch implements Helper {
|
||||
|
||||
private final HashSet<Long> favoredPositions;
|
||||
private final Favoring favoring;
|
||||
private final CalculationContext calcContext;
|
||||
|
||||
public AStarPathFinder(int startX, int startY, int startZ, Goal goal, HashSet<Long> favoredPositions, CalculationContext context) {
|
||||
public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Favoring favoring, CalculationContext context) {
|
||||
super(startX, startY, startZ, goal, context);
|
||||
this.favoredPositions = favoredPositions;
|
||||
this.favoring = favoring;
|
||||
this.calcContext = context;
|
||||
}
|
||||
|
||||
|
@ -56,7 +59,6 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
startNode.combinedCost = startNode.estimatedCostToGoal;
|
||||
BinaryHeapOpenSet openSet = new BinaryHeapOpenSet();
|
||||
openSet.insert(startNode);
|
||||
startNode.isOpen = true;
|
||||
bestSoFar = new PathNode[COEFFICIENTS.length];//keep track of the best node by the metric of (estimatedCostToGoal + cost / COEFFICIENTS[i])
|
||||
double[] bestHeuristicSoFar = new double[COEFFICIENTS.length];
|
||||
for (int i = 0; i < bestHeuristicSoFar.length; i++) {
|
||||
|
@ -64,9 +66,9 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
bestSoFar[i] = startNode;
|
||||
}
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
HashSet<Long> favored = favoredPositions;
|
||||
BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world().getWorldBorder());
|
||||
long startTime = System.nanoTime() / 1000000L;
|
||||
Favoring favored = favoring;
|
||||
BetterWorldBorder worldBorder = new BetterWorldBorder(calcContext.world.getWorldBorder());
|
||||
long startTime = System.currentTimeMillis();
|
||||
boolean slowPath = Baritone.settings().slowPath.get();
|
||||
if (slowPath) {
|
||||
logDebug("slowPath is on, path timeout will be " + Baritone.settings().slowPathTimeoutMS.<Long>get() + "ms instead of " + primaryTimeout + "ms");
|
||||
|
@ -77,9 +79,9 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
int numNodes = 0;
|
||||
int numMovementsConsidered = 0;
|
||||
int numEmptyChunk = 0;
|
||||
boolean favoring = favored != null;
|
||||
boolean favoring = !favored.isEmpty();
|
||||
int timeCheckInterval = 1 << 6;
|
||||
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();
|
||||
|
||||
long[] timeConsumed = new long[Moves.values().length];
|
||||
|
@ -106,10 +108,12 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
long startVal3 = BetterBlockPos.numCreated;
|
||||
|
||||
while (!openSet.isEmpty() && numEmptyChunk < pathingMaxChunkBorderFetch && !cancelRequested) {
|
||||
long now = System.nanoTime() / 1000000L;
|
||||
if ((numNodes & (timeCheckInterval - 1)) == 0) { // only call this once every 64 nodes (about half a millisecond)
|
||||
long now = System.currentTimeMillis(); // since nanoTime is slow on windows (takes many microseconds)
|
||||
if (now - failureTimeoutTime >= 0 || (!failing && now - primaryTimeoutTime >= 0)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (slowPath) {
|
||||
try {
|
||||
Thread.sleep(Baritone.settings().slowPathTimeDelayMS.<Long>get());
|
||||
|
@ -121,11 +125,10 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
long t = System.nanoTime();
|
||||
heapRemove += t - before;
|
||||
heapRemoveCount++;
|
||||
currentNode.isOpen = false;
|
||||
mostRecentConsidered = currentNode;
|
||||
numNodes++;
|
||||
if (goal.isInGoal(currentNode.x, currentNode.y, currentNode.z)) {
|
||||
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, " + numMovementsConsidered + " movements considered");
|
||||
logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, " + numMovementsConsidered + " movements considered");
|
||||
return Optional.of(new Path(startNode, currentNode, numNodes, goal, calcContext));
|
||||
}
|
||||
goalCheck += System.nanoTime() - t;
|
||||
|
@ -168,13 +171,13 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
if (actionCost >= ActionCosts.COST_INF) {
|
||||
continue;
|
||||
}
|
||||
if (actionCost <= 0) {
|
||||
if (actionCost <= 0 || Double.isNaN(actionCost)) {
|
||||
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
|
||||
}
|
||||
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
|
||||
if (moves.dynamicXZ && !worldBorder.entirelyContains(res.x, res.z)) { // see issue #218
|
||||
continue;
|
||||
}
|
||||
// check destination after verifying it's not COST_INF -- some movements return a static IMPOSSIBLE object with COST_INF and destination being 0,0,0 to avoid allocating a new result for every failed calculation
|
||||
if (!moves.dynamicXZ && (res.x != newX || res.z != newZ)) {
|
||||
throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
|
||||
}
|
||||
|
@ -182,9 +185,9 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
throw new IllegalStateException(moves + " " + res.y + " " + (currentNode.y + moves.yOffset));
|
||||
}
|
||||
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
|
||||
if (favoring && favored.contains(hashCode)) {
|
||||
if (favoring) {
|
||||
// see issue #18
|
||||
actionCost *= favorCoeff;
|
||||
actionCost *= favored.calculate(hashCode);
|
||||
}
|
||||
long st = System.nanoTime();
|
||||
PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode);
|
||||
|
@ -192,9 +195,6 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
getNodeCount++;
|
||||
double tentativeCost = currentNode.cost + actionCost;
|
||||
if (tentativeCost < neighbor.cost) {
|
||||
if (tentativeCost < 0) {
|
||||
throw new IllegalStateException(moves + " overflowed into negative " + actionCost + " " + neighbor.cost + " " + tentativeCost);
|
||||
}
|
||||
double improvementBy = neighbor.cost - tentativeCost;
|
||||
// there are floating point errors caused by random combinations of traverse and diagonal over a flat area
|
||||
// that means that sometimes there's a cost improvement of like 10 ^ -16
|
||||
|
@ -206,7 +206,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
neighbor.previous = currentNode;
|
||||
neighbor.cost = tentativeCost;
|
||||
neighbor.combinedCost = tentativeCost + neighbor.estimatedCostToGoal;
|
||||
if (neighbor.isOpen) {
|
||||
if (neighbor.isOpen()) {
|
||||
long bef = System.nanoTime();
|
||||
openSet.update(neighbor);
|
||||
heapUpdate += System.nanoTime() - bef;
|
||||
|
@ -216,7 +216,6 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
openSet.insert(neighbor);//dont double count, dont insert into open set if it's already there
|
||||
heapAdd += System.nanoTime() - bef;
|
||||
heapAddCount++;
|
||||
neighbor.isOpen = true;
|
||||
}
|
||||
for (int i = 0; i < bestSoFar.length; i++) {
|
||||
double heuristic = neighbor.estimatedCostToGoal + neighbor.cost / COEFFICIENTS[i];
|
||||
|
@ -270,7 +269,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
System.out.println(numMovementsConsidered + " movements considered");
|
||||
System.out.println("Open set size: " + openSet.size());
|
||||
System.out.println("PathNode map size: " + mapSize());
|
||||
System.out.println((int) (numNodes * 1.0 / ((System.nanoTime() / 1000000L - startTime) / 1000F)) + " nodes per second");
|
||||
System.out.println((int) (numNodes * 1.0 / ((System.currentTimeMillis() - startTime) / 1000F)) + " nodes per second");
|
||||
double bestDist = 0;
|
||||
for (int i = 0; i < bestSoFar.length; i++) {
|
||||
if (bestSoFar[i] == null) {
|
||||
|
@ -281,7 +280,7 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
|
|||
bestDist = dist;
|
||||
}
|
||||
if (dist > MIN_DIST_PATH * MIN_DIST_PATH) { // square the comparison since distFromStartSq is squared
|
||||
logDebug("Took " + (System.nanoTime() / 1000000L - startTime) + "ms, A* cost coefficient " + COEFFICIENTS[i] + ", " + numMovementsConsidered + " movements considered");
|
||||
logDebug("Took " + (System.currentTimeMillis() - startTime) + "ms, A* cost coefficient " + COEFFICIENTS[i] + ", " + numMovementsConsidered + " movements considered");
|
||||
if (COEFFICIENTS[i] >= 3) {
|
||||
System.out.println("Warning: cost coefficient is greater than three! Probably means that");
|
||||
System.out.println("the path I found is pretty terrible (like sneak-bridging for dozens of blocks)");
|
||||
|
|
|
@ -21,6 +21,7 @@ import baritone.Baritone;
|
|||
import baritone.api.pathing.calc.IPath;
|
||||
import baritone.api.pathing.calc.IPathFinder;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.PathCalculationResult;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.utils.Helper;
|
||||
|
@ -86,7 +87,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
|
|||
@Override
|
||||
public synchronized PathCalculationResult calculate(long primaryTimeout, long failureTimeout) {
|
||||
if (isFinished) {
|
||||
throw new IllegalStateException("Path Finder is currently in use, and cannot be reused!");
|
||||
throw new IllegalStateException("Path finder cannot be reused!");
|
||||
}
|
||||
cancelRequested = false;
|
||||
try {
|
||||
|
@ -135,9 +136,14 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
|
|||
* for the node mapped to the specified pos. If no node is found,
|
||||
* a new node is created.
|
||||
*
|
||||
* @param x The x position of the node
|
||||
* @param y The y position of the node
|
||||
* @param z The z position of the node
|
||||
* @param hashCode The hash code of the node, provided by {@link BetterBlockPos#longHash(int, int, int)}
|
||||
* @return The associated node
|
||||
* @see <a href="https://github.com/cabaletta/baritone/issues/107">Issue #107</a>
|
||||
*/
|
||||
|
||||
protected PathNode getNodeAtPosition(int x, int y, int z, long hashCode) {
|
||||
PathNode node = map.get(hashCode);
|
||||
if (node == null) {
|
||||
|
|
|
@ -132,7 +132,9 @@ class Path extends PathBase {
|
|||
Movement move = moves.apply0(context, src);
|
||||
if (move.getDest().equals(dest)) {
|
||||
// have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution
|
||||
move.override(cost);
|
||||
// however, taking into account possible favoring that could skew the node cost, we really want the stricter limit of the two
|
||||
// so we take the minimum of the path node cost difference, and the calculated cost
|
||||
move.override(Math.min(move.calculateCost(context), cost));
|
||||
return move;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,12 +58,6 @@ public final class PathNode {
|
|||
*/
|
||||
public PathNode previous;
|
||||
|
||||
/**
|
||||
* Is this a member of the open set in A*? (only used during pathfinding)
|
||||
* Instead of doing a costly member check in the open set, cache membership in each node individually too.
|
||||
*/
|
||||
public boolean isOpen;
|
||||
|
||||
/**
|
||||
* Where is this node in the array flattenization of the binary heap? Needed for decrease-key operations.
|
||||
*/
|
||||
|
@ -73,12 +67,19 @@ public final class PathNode {
|
|||
this.previous = null;
|
||||
this.cost = ActionCosts.COST_INF;
|
||||
this.estimatedCostToGoal = goal.heuristic(x, y, z);
|
||||
this.isOpen = false;
|
||||
if (Double.isNaN(estimatedCostToGoal)) {
|
||||
throw new IllegalStateException(goal + " calculated implausible heuristic");
|
||||
}
|
||||
this.heapPosition = -1;
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public boolean isOpen() {
|
||||
return heapPosition != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Possibly reimplement hashCode and equals. They are necessary for this class to function but they could be done better
|
||||
*
|
||||
|
|
|
@ -59,7 +59,7 @@ public final class BinaryHeapOpenSet implements IOpenSet {
|
|||
@Override
|
||||
public final void insert(PathNode value) {
|
||||
if (size >= array.length - 1) {
|
||||
array = Arrays.copyOf(array, array.length * 2);
|
||||
array = Arrays.copyOf(array, array.length << 1);
|
||||
}
|
||||
size++;
|
||||
value.heapPosition = size;
|
||||
|
|
|
@ -42,36 +42,50 @@ public class CalculationContext {
|
|||
|
||||
private static final ItemStack STACK_BUCKET_WATER = new ItemStack(Items.WATER_BUCKET);
|
||||
|
||||
private final IBaritone baritone;
|
||||
private final EntityPlayerSP player;
|
||||
private final World world;
|
||||
private final WorldData worldData;
|
||||
private final BlockStateInterface bsi;
|
||||
private final ToolSet toolSet;
|
||||
private final boolean hasWaterBucket;
|
||||
private final boolean hasThrowaway;
|
||||
private final boolean canSprint;
|
||||
private final double placeBlockCost;
|
||||
private final boolean allowBreak;
|
||||
private final int maxFallHeightNoWater;
|
||||
private final int maxFallHeightBucket;
|
||||
private final double waterWalkSpeed;
|
||||
private final double breakBlockAdditionalCost;
|
||||
private final BetterWorldBorder worldBorder;
|
||||
public final IBaritone baritone;
|
||||
public final World world;
|
||||
public final WorldData worldData;
|
||||
public final BlockStateInterface bsi;
|
||||
public final ToolSet toolSet;
|
||||
public final boolean hasWaterBucket;
|
||||
public final boolean hasThrowaway;
|
||||
public final boolean canSprint;
|
||||
public final double placeBlockCost;
|
||||
public final boolean allowBreak;
|
||||
public final boolean allowParkour;
|
||||
public final boolean allowParkourPlace;
|
||||
public final boolean allowJumpAt256;
|
||||
public final boolean assumeWalkOnWater;
|
||||
public final boolean allowDiagonalDescend;
|
||||
public final int maxFallHeightNoWater;
|
||||
public final int maxFallHeightBucket;
|
||||
public final double waterWalkSpeed;
|
||||
public final double breakBlockAdditionalCost;
|
||||
public final double jumpPenalty;
|
||||
public final double walkOnWaterOnePenalty;
|
||||
public final BetterWorldBorder worldBorder;
|
||||
|
||||
public CalculationContext(IBaritone baritone) {
|
||||
this(baritone, false);
|
||||
}
|
||||
|
||||
public CalculationContext(IBaritone baritone, boolean forUseOnAnotherThread) {
|
||||
this.baritone = baritone;
|
||||
this.player = baritone.getPlayerContext().player();
|
||||
EntityPlayerSP player = baritone.getPlayerContext().player();
|
||||
this.world = baritone.getPlayerContext().world();
|
||||
this.worldData = (WorldData) baritone.getWorldProvider().getCurrentWorld();
|
||||
this.bsi = new BlockStateInterface(world, worldData); // TODO TODO TODO
|
||||
// new CalculationContext() needs to happen, can't add an argument (i'll beat you), can we get the world provider from currentlyTicking?
|
||||
this.bsi = new BlockStateInterface(world, worldData, forUseOnAnotherThread); // TODO TODO TODO
|
||||
this.toolSet = new ToolSet(player);
|
||||
this.hasThrowaway = Baritone.settings().allowPlace.get() && MovementHelper.throwaway(baritone.getPlayerContext(), false);
|
||||
this.hasWaterBucket = Baritone.settings().allowWaterBucketFall.get() && InventoryPlayer.isHotbar(player.inventory.getSlotFor(STACK_BUCKET_WATER)) && !world.provider.isNether();
|
||||
this.canSprint = Baritone.settings().allowSprint.get() && player.getFoodStats().getFoodLevel() > 6;
|
||||
this.placeBlockCost = Baritone.settings().blockPlacementPenalty.get();
|
||||
this.allowBreak = Baritone.settings().allowBreak.get();
|
||||
this.allowParkour = Baritone.settings().allowParkour.get();
|
||||
this.allowParkourPlace = Baritone.settings().allowParkourPlace.get();
|
||||
this.allowJumpAt256 = Baritone.settings().allowJumpAt256.get();
|
||||
this.assumeWalkOnWater = Baritone.settings().assumeWalkOnWater.get();
|
||||
this.allowDiagonalDescend = Baritone.settings().allowDiagonalDescend.get();
|
||||
this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.get();
|
||||
this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.get();
|
||||
int depth = EnchantmentHelper.getDepthStriderModifier(player);
|
||||
|
@ -81,6 +95,8 @@ public class CalculationContext {
|
|||
float mult = depth / 3.0F;
|
||||
this.waterWalkSpeed = ActionCosts.WALK_ONE_IN_WATER_COST * (1 - mult) + ActionCosts.WALK_ONE_BLOCK_COST * mult;
|
||||
this.breakBlockAdditionalCost = Baritone.settings().blockBreakAdditionalPenalty.get();
|
||||
this.jumpPenalty = Baritone.settings().jumpPenalty.get();
|
||||
this.walkOnWaterOnePenalty = Baritone.settings().walkOnWaterOnePenalty.get();
|
||||
// why cache these things here, why not let the movements just get directly from settings?
|
||||
// because if some movements are calculated one way and others are calculated another way,
|
||||
// then you get a wildly inconsistent path that isn't optimal for either scenario.
|
||||
|
@ -108,7 +124,7 @@ public class CalculationContext {
|
|||
}
|
||||
|
||||
public boolean canPlaceThrowawayAt(int x, int y, int z) {
|
||||
if (!hasThrowaway()) { // only true if allowPlace is true, see constructor
|
||||
if (!hasThrowaway) { // only true if allowPlace is true, see constructor
|
||||
return false;
|
||||
}
|
||||
if (isPossiblyProtected(x, y, z)) {
|
||||
|
@ -118,7 +134,7 @@ public class CalculationContext {
|
|||
}
|
||||
|
||||
public boolean canBreakAt(int x, int y, int z) {
|
||||
if (!allowBreak()) {
|
||||
if (!allowBreak) {
|
||||
return false;
|
||||
}
|
||||
return !isPossiblyProtected(x, y, z);
|
||||
|
@ -128,60 +144,4 @@ public class CalculationContext {
|
|||
// TODO more protection logic here; see #220
|
||||
return false;
|
||||
}
|
||||
|
||||
public World world() {
|
||||
return world;
|
||||
}
|
||||
|
||||
public EntityPlayerSP player() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public BlockStateInterface bsi() {
|
||||
return bsi;
|
||||
}
|
||||
|
||||
public WorldData worldData() {
|
||||
return worldData;
|
||||
}
|
||||
|
||||
public ToolSet getToolSet() {
|
||||
return toolSet;
|
||||
}
|
||||
|
||||
public boolean hasWaterBucket() {
|
||||
return hasWaterBucket;
|
||||
}
|
||||
|
||||
public boolean hasThrowaway() {
|
||||
return hasThrowaway;
|
||||
}
|
||||
|
||||
public boolean canSprint() {
|
||||
return canSprint;
|
||||
}
|
||||
|
||||
public double placeBlockCost() {
|
||||
return placeBlockCost;
|
||||
}
|
||||
|
||||
public boolean allowBreak() {
|
||||
return allowBreak;
|
||||
}
|
||||
|
||||
public int maxFallHeightNoWater() {
|
||||
return maxFallHeightNoWater;
|
||||
}
|
||||
|
||||
public int maxFallHeightBucket() {
|
||||
return maxFallHeightBucket;
|
||||
}
|
||||
|
||||
public double waterWalkSpeed() {
|
||||
return waterWalkSpeed;
|
||||
}
|
||||
|
||||
public double breakBlockAdditionalCost() {
|
||||
return breakBlockAdditionalCost;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import baritone.utils.BlockStateInterface;
|
|||
import net.minecraft.block.BlockLiquid;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -35,7 +34,7 @@ import java.util.Optional;
|
|||
|
||||
public abstract class Movement implements IMovement, MovementHelper {
|
||||
|
||||
protected static final EnumFacing[] HORIZONTALS = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST};
|
||||
protected static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN};
|
||||
|
||||
protected final IBaritone baritone;
|
||||
protected final IPlayerContext ctx;
|
||||
|
@ -85,7 +84,7 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
return cost;
|
||||
}
|
||||
|
||||
protected abstract double calculateCost(CalculationContext context);
|
||||
public abstract double calculateCost(CalculationContext context);
|
||||
|
||||
@Override
|
||||
public double recalculateCost() {
|
||||
|
@ -125,13 +124,10 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
rotation,
|
||||
currentState.getTarget().hasToForceRotations()));
|
||||
|
||||
// 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
|
||||
|
||||
currentState.getInputStates().forEach((input, forced) -> {
|
||||
baritone.getInputOverrideHandler().setInputForceState(input, forced);
|
||||
});
|
||||
currentState.getInputStates().replaceAll((input, forced) -> false);
|
||||
currentState.getInputStates().clear();
|
||||
|
||||
// If the current status indicates a completed movement
|
||||
if (currentState.getStatus().isComplete()) {
|
||||
|
@ -151,9 +147,10 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
somethingInTheWay = true;
|
||||
Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), blockPos, ctx.playerController().getBlockReachDistance());
|
||||
if (reachable.isPresent()) {
|
||||
Rotation rotTowardsBlock = reachable.get();
|
||||
MovementHelper.switchToBestToolFor(ctx, BlockStateInterface.get(ctx, blockPos));
|
||||
state.setTarget(new MovementState.MovementTarget(reachable.get(), true));
|
||||
if (Objects.equals(ctx.getSelectedBlock().orElse(null), blockPos)) {
|
||||
state.setTarget(new MovementState.MovementTarget(rotTowardsBlock, true));
|
||||
if (Objects.equals(ctx.getSelectedBlock().orElse(null), blockPos) || ctx.playerRotations().isReallyCloseTo(rotTowardsBlock)) {
|
||||
state.setInput(Input.CLICK_LEFT, true);
|
||||
}
|
||||
return false;
|
||||
|
@ -204,10 +201,10 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
}
|
||||
|
||||
/**
|
||||
* Calculate latest movement state.
|
||||
* Gets called once a tick.
|
||||
* Calculate latest movement state. Gets called once a tick.
|
||||
*
|
||||
* @return
|
||||
* @param state The current state
|
||||
* @return The new state
|
||||
*/
|
||||
public MovementState updateState(MovementState state) {
|
||||
if (!prepared(state)) {
|
||||
|
@ -229,7 +226,7 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
}
|
||||
|
||||
public void checkLoadedChunk(CalculationContext context) {
|
||||
calculatedWhileLoaded = !(context.world().getChunk(getDest()) instanceof EmptyChunk);
|
||||
calculatedWhileLoaded = context.bsi.worldContainsLoadedChunk(dest.x, dest.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -244,14 +241,13 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
toWalkIntoCached = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> toBreak() {
|
||||
public List<BlockPos> toBreak(BlockStateInterface bsi) {
|
||||
if (toBreakCached != null) {
|
||||
return toBreakCached;
|
||||
}
|
||||
List<BlockPos> result = new ArrayList<>();
|
||||
for (BetterBlockPos positionToBreak : positionsToBreak) {
|
||||
if (!MovementHelper.canWalkThrough(ctx, positionToBreak)) {
|
||||
if (!MovementHelper.canWalkThrough(bsi, positionToBreak.x, positionToBreak.y, positionToBreak.z)) {
|
||||
result.add(positionToBreak);
|
||||
}
|
||||
}
|
||||
|
@ -259,21 +255,19 @@ public abstract class Movement implements IMovement, MovementHelper {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> toPlace() {
|
||||
public List<BlockPos> toPlace(BlockStateInterface bsi) {
|
||||
if (toPlaceCached != null) {
|
||||
return toPlaceCached;
|
||||
}
|
||||
List<BlockPos> result = new ArrayList<>();
|
||||
if (positionToPlace != null && !MovementHelper.canWalkOn(ctx, positionToPlace)) {
|
||||
if (positionToPlace != null && !MovementHelper.canWalkOn(bsi, positionToPlace.x, positionToPlace.y, positionToPlace.z)) {
|
||||
result.add(positionToPlace);
|
||||
}
|
||||
toPlaceCached = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
|
||||
public List<BlockPos> toWalkInto(BlockStateInterface bsi) { // overridden by movementdiagonal
|
||||
if (toWalkIntoCached == null) {
|
||||
toWalkIntoCached = new ArrayList<>();
|
||||
}
|
||||
|
|
|
@ -35,8 +35,6 @@ import net.minecraft.item.ItemStack;
|
|||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.NonNullList;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
/**
|
||||
* Static helpers for cost calculation
|
||||
|
@ -70,7 +68,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
if (block == Blocks.AIR) { // early return for most common case
|
||||
return true;
|
||||
}
|
||||
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL) {
|
||||
if (block == Blocks.FIRE || block == Blocks.TRIPWIRE || block == Blocks.WEB || block == Blocks.END_PORTAL || block == Blocks.COCOA) {
|
||||
return false;
|
||||
}
|
||||
if (block instanceof BlockDoor || block instanceof BlockFenceGate) {
|
||||
|
@ -92,7 +90,11 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
if (snow) {
|
||||
// the check in BlockSnow.isPassable is layers < 5
|
||||
// while actually, we want < 3 because 3 or greater makes it impassable in a 2 high ceiling
|
||||
return state.getValue(BlockSnow.LAYERS) < 3;
|
||||
if (state.getValue(BlockSnow.LAYERS) >= 3) {
|
||||
return false;
|
||||
}
|
||||
// ok, it's low enough we could walk through it, but is it supported?
|
||||
return canWalkOn(bsi, x, y - 1, z);
|
||||
}
|
||||
if (trapdoor) {
|
||||
return !state.getValue(BlockTrapDoor.OPEN); // see BlockTrapDoor.isPassable
|
||||
|
@ -122,7 +124,11 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
* canWalkThrough but also won't impede movement at all. so not including doors or fence gates (we'd have to right click),
|
||||
* not including water, and not including ladders or vines or cobwebs (they slow us down)
|
||||
*
|
||||
* @return
|
||||
* @param context Calculation context to provide block state lookup
|
||||
* @param x The block's x position
|
||||
* @param y The block's y position
|
||||
* @param z The block's z position
|
||||
* @return Whether or not the block at the specified position
|
||||
*/
|
||||
static boolean fullyPassable(CalculationContext context, int x, int y, int z) {
|
||||
return fullyPassable(context.get(x, y, z));
|
||||
|
@ -139,6 +145,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
|| block == Blocks.WEB
|
||||
|| block == Blocks.VINE
|
||||
|| block == Blocks.LADDER
|
||||
|| block == Blocks.COCOA
|
||||
|| block instanceof BlockDoor
|
||||
|| block instanceof BlockFenceGate
|
||||
|| block instanceof BlockSnow
|
||||
|
@ -151,7 +158,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
return block.isPassable(null, null);
|
||||
}
|
||||
|
||||
static boolean isReplacable(int x, int y, int z, IBlockState state, World world) {
|
||||
static boolean isReplacable(int x, int y, int z, IBlockState state, BlockStateInterface bsi) {
|
||||
// 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
|
||||
|
@ -163,9 +170,13 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
* }
|
||||
*/
|
||||
Block block = state.getBlock();
|
||||
if (block == Blocks.AIR || isWater(block)) {
|
||||
// early return for common cases hehe
|
||||
return true;
|
||||
}
|
||||
if (block instanceof BlockSnow) {
|
||||
// as before, default to true (mostly because it would otherwise make long distance pathing through snowy biomes impossible)
|
||||
if (world.getChunk(x >> 4, z >> 4) instanceof EmptyChunk) {
|
||||
if (!bsi.worldContainsLoadedChunk(x, z)) {
|
||||
return true;
|
||||
}
|
||||
return state.getValue(BlockSnow.LAYERS) == 1;
|
||||
|
@ -238,7 +249,12 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
* through? Includes water because we know that we automatically jump on
|
||||
* water
|
||||
*
|
||||
* @return
|
||||
* @param bsi Block state provider
|
||||
* @param x The block's x position
|
||||
* @param y The block's y position
|
||||
* @param z The block's z position
|
||||
* @param state The state of the block at the specified location
|
||||
* @return Whether or not the specified block can be walked on
|
||||
*/
|
||||
static boolean canWalkOn(BlockStateInterface bsi, int x, int y, int z, IBlockState state) {
|
||||
Block block = state.getBlock();
|
||||
|
@ -324,24 +340,24 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
|
||||
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, IBlockState state, boolean includeFalling) {
|
||||
Block block = state.getBlock();
|
||||
if (!canWalkThrough(context.bsi(), x, y, z, state)) {
|
||||
if (!canWalkThrough(context.bsi, x, y, z, state)) {
|
||||
if (!context.canBreakAt(x, y, z)) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (avoidBreaking(context.bsi(), x, y, z, state)) {
|
||||
if (avoidBreaking(context.bsi, x, y, z, state)) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (block instanceof BlockLiquid) {
|
||||
return COST_INF;
|
||||
}
|
||||
double m = Blocks.CRAFTING_TABLE.equals(block) ? 10 : 1; // TODO see if this is still necessary. it's from MineBot when we wanted to penalize breaking its crafting table
|
||||
double strVsBlock = context.getToolSet().getStrVsBlock(state);
|
||||
double strVsBlock = context.toolSet.getStrVsBlock(state);
|
||||
if (strVsBlock <= 0) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
||||
double result = m / strVsBlock;
|
||||
result += context.breakBlockAdditionalCost();
|
||||
result += context.breakBlockAdditionalCost;
|
||||
if (includeFalling) {
|
||||
IBlockState above = context.get(x, y + 1, z);
|
||||
if (above.getBlock() instanceof BlockFalling) {
|
||||
|
@ -362,6 +378,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
/**
|
||||
* AutoTool for a specific block
|
||||
*
|
||||
* @param ctx The player context
|
||||
* @param b the blockstate to mine
|
||||
*/
|
||||
static void switchToBestToolFor(IPlayerContext ctx, IBlockState b) {
|
||||
|
@ -371,6 +388,7 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
/**
|
||||
* AutoTool for a specific block with precomputed ToolSet data
|
||||
*
|
||||
* @param ctx The player context
|
||||
* @param b the blockstate to mine
|
||||
* @param ts previously calculated ToolSet
|
||||
*/
|
||||
|
@ -465,7 +483,6 @@ public interface MovementHelper extends ActionCosts, Helper {
|
|||
static boolean isFlowing(IBlockState state) {
|
||||
// Will be IFluidState in 1.13
|
||||
return state.getBlock() instanceof BlockLiquid
|
||||
&& state.getPropertyKeys().contains(BlockLiquid.LEVEL)
|
||||
&& state.getValue(BlockLiquid.LEVEL) != 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package baritone.pathing.movement;
|
|||
import baritone.api.pathing.movement.MovementStatus;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.input.Input;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -29,7 +28,6 @@ import java.util.Optional;
|
|||
public class MovementState {
|
||||
|
||||
private MovementStatus status;
|
||||
private MovementTarget goal = new MovementTarget();
|
||||
private MovementTarget target = new MovementTarget();
|
||||
private final Map<Input, Boolean> inputState = new HashMap<>();
|
||||
|
||||
|
@ -42,15 +40,6 @@ public class MovementState {
|
|||
return status;
|
||||
}
|
||||
|
||||
public MovementTarget getGoal() {
|
||||
return this.goal;
|
||||
}
|
||||
|
||||
public MovementState setGoal(MovementTarget goal) {
|
||||
this.goal = goal;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MovementTarget getTarget() {
|
||||
return this.target;
|
||||
}
|
||||
|
@ -65,23 +54,12 @@ public class MovementState {
|
|||
return this;
|
||||
}
|
||||
|
||||
public boolean getInput(Input input) {
|
||||
return this.inputState.getOrDefault(input, false);
|
||||
}
|
||||
|
||||
public Map<Input, Boolean> getInputStates() {
|
||||
return this.inputState;
|
||||
}
|
||||
|
||||
public static class MovementTarget {
|
||||
|
||||
/**
|
||||
* Necessary movement to achieve
|
||||
* <p>
|
||||
* TODO: Decide desiredMovement type
|
||||
*/
|
||||
public Vec3d position;
|
||||
|
||||
/**
|
||||
* Yaw and pitch angles that must be matched
|
||||
*/
|
||||
|
@ -95,27 +73,14 @@ public class MovementState {
|
|||
private boolean forceRotations;
|
||||
|
||||
public MovementTarget() {
|
||||
this(null, null, false);
|
||||
}
|
||||
|
||||
public MovementTarget(Vec3d position) {
|
||||
this(position, null, false);
|
||||
this(null, false);
|
||||
}
|
||||
|
||||
public MovementTarget(Rotation rotation, boolean forceRotations) {
|
||||
this(null, rotation, forceRotations);
|
||||
}
|
||||
|
||||
public MovementTarget(Vec3d position, Rotation rotation, boolean forceRotations) {
|
||||
this.position = position;
|
||||
this.rotation = rotation;
|
||||
this.forceRotations = forceRotations;
|
||||
}
|
||||
|
||||
public final Optional<Vec3d> getPosition() {
|
||||
return Optional.ofNullable(this.position);
|
||||
}
|
||||
|
||||
public final Optional<Rotation> getRotation() {
|
||||
return Optional.ofNullable(this.rotation);
|
||||
}
|
||||
|
|
|
@ -220,51 +220,59 @@ public enum Moves {
|
|||
}
|
||||
},
|
||||
|
||||
DIAGONAL_NORTHEAST(+1, 0, -1) {
|
||||
DIAGONAL_NORTHEAST(+1, 0, -1, false, true) {
|
||||
@Override
|
||||
public Movement apply0(CalculationContext context, BetterBlockPos src) {
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.EAST);
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
apply(context, src.x, src.y, src.z, res);
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.EAST, res.y - src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double cost(CalculationContext context, int x, int y, int z) {
|
||||
return MovementDiagonal.cost(context, x, y, z, x + 1, z - 1);
|
||||
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
|
||||
MovementDiagonal.cost(context, x, y, z, x + 1, z - 1, result);
|
||||
}
|
||||
},
|
||||
|
||||
DIAGONAL_NORTHWEST(-1, 0, -1) {
|
||||
DIAGONAL_NORTHWEST(-1, 0, -1, false, true) {
|
||||
@Override
|
||||
public Movement apply0(CalculationContext context, BetterBlockPos src) {
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.WEST);
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
apply(context, src.x, src.y, src.z, res);
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.NORTH, EnumFacing.WEST, res.y - src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double cost(CalculationContext context, int x, int y, int z) {
|
||||
return MovementDiagonal.cost(context, x, y, z, x - 1, z - 1);
|
||||
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
|
||||
MovementDiagonal.cost(context, x, y, z, x - 1, z - 1, result);
|
||||
}
|
||||
},
|
||||
|
||||
DIAGONAL_SOUTHEAST(+1, 0, +1) {
|
||||
DIAGONAL_SOUTHEAST(+1, 0, +1, false, true) {
|
||||
@Override
|
||||
public Movement apply0(CalculationContext context, BetterBlockPos src) {
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.EAST);
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
apply(context, src.x, src.y, src.z, res);
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.EAST, res.y - src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double cost(CalculationContext context, int x, int y, int z) {
|
||||
return MovementDiagonal.cost(context, x, y, z, x + 1, z + 1);
|
||||
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
|
||||
MovementDiagonal.cost(context, x, y, z, x + 1, z + 1, result);
|
||||
}
|
||||
},
|
||||
|
||||
DIAGONAL_SOUTHWEST(-1, 0, +1) {
|
||||
DIAGONAL_SOUTHWEST(-1, 0, +1, false, true) {
|
||||
@Override
|
||||
public Movement apply0(CalculationContext context, BetterBlockPos src) {
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.WEST);
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
apply(context, src.x, src.y, src.z, res);
|
||||
return new MovementDiagonal(context.getBaritone(), src, EnumFacing.SOUTH, EnumFacing.WEST, res.y - src.y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double cost(CalculationContext context, int x, int y, int z) {
|
||||
return MovementDiagonal.cost(context, x, y, z, x - 1, z + 1);
|
||||
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
|
||||
MovementDiagonal.cost(context, x, y, z, x - 1, z + 1, result);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -52,41 +52,28 @@ public class MovementAscend extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
return cost(context, src.x, src.y, src.z, dest.x, dest.z);
|
||||
}
|
||||
|
||||
public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
|
||||
IBlockState srcDown = context.get(x, y - 1, z);
|
||||
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
|
||||
return COST_INF;
|
||||
}
|
||||
// we can jump from soul sand, but not from a bottom slab
|
||||
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
|
||||
IBlockState toPlace = context.get(destX, y, destZ);
|
||||
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
|
||||
|
||||
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
|
||||
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
|
||||
}
|
||||
boolean hasToPlace = false;
|
||||
if (!MovementHelper.canWalkOn(context.bsi(), destX, y, destZ, toPlace)) {
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y, destZ, toPlace)) {
|
||||
if (!context.canPlaceThrowawayAt(destX, y, destZ)) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace, context.world())) {
|
||||
if (!MovementHelper.isReplacable(destX, y, destZ, toPlace, context.bsi)) {
|
||||
return COST_INF;
|
||||
}
|
||||
// TODO: add ability to place against .down() as well as the cardinal directions
|
||||
// useful for when you are starting a staircase without anything to place against
|
||||
// Counterpoint to the above TODO ^ you should move then pillar instead of ascend
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int againstX = destX + HORIZONTALS[i].getXOffset();
|
||||
int againstZ = destZ + HORIZONTALS[i].getZOffset();
|
||||
if (againstX == x && againstZ == z) {
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
|
||||
int againstY = y + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset();
|
||||
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset();
|
||||
if (againstX == x && againstZ == z) { // we might be able to backplace now, but it doesn't matter because it will have been broken by the time we'd need to use it
|
||||
continue;
|
||||
}
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y, againstZ)) {
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) {
|
||||
hasToPlace = true;
|
||||
break;
|
||||
}
|
||||
|
@ -95,8 +82,8 @@ public class MovementAscend extends Movement {
|
|||
return COST_INF;
|
||||
}
|
||||
}
|
||||
IBlockState srcUp2 = null;
|
||||
if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context.bsi(), x, y + 1, z) || !((srcUp2 = context.get(x, y + 2, z)).getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us
|
||||
IBlockState srcUp2 = context.get(x, y + 2, z); // used lower down anyway
|
||||
if (context.get(x, y + 3, z).getBlock() instanceof BlockFalling && (MovementHelper.canWalkThrough(context.bsi, x, y + 1, z) || !(srcUp2.getBlock() instanceof BlockFalling))) {//it would fall on us and possibly suffocate us
|
||||
// HOWEVER, we assume that we're standing in the start position
|
||||
// that means that src and src.up(1) are both air
|
||||
// maybe they aren't now, but they will be by the time this starts
|
||||
|
@ -114,32 +101,41 @@ public class MovementAscend extends Movement {
|
|||
// it's possible srcUp is AIR from the start, and srcUp2 is falling
|
||||
// and in that scenario, when we arrive and break srcUp2, that lets srcUp3 fall on us and suffocate us
|
||||
}
|
||||
IBlockState srcDown = context.get(x, y - 1, z);
|
||||
if (srcDown.getBlock() == Blocks.LADDER || srcDown.getBlock() == Blocks.VINE) {
|
||||
return COST_INF;
|
||||
}
|
||||
// we can jump from soul sand, but not from a bottom slab
|
||||
boolean jumpingFromBottomSlab = MovementHelper.isBottomSlab(srcDown);
|
||||
boolean jumpingToBottomSlab = MovementHelper.isBottomSlab(toPlace);
|
||||
if (jumpingFromBottomSlab && !jumpingToBottomSlab) {
|
||||
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
|
||||
}
|
||||
double walk;
|
||||
if (jumpingToBottomSlab) {
|
||||
if (jumpingFromBottomSlab) {
|
||||
walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST); // we hit space immediately on entering this action
|
||||
walk += context.jumpPenalty;
|
||||
} else {
|
||||
walk = WALK_ONE_BLOCK_COST; // we don't hit space we just walk into the slab
|
||||
}
|
||||
} else {
|
||||
// jumpingFromBottomSlab must be false
|
||||
if (toPlace.getBlock() == Blocks.SOUL_SAND) {
|
||||
walk = WALK_ONE_OVER_SOUL_SAND_COST;
|
||||
} else {
|
||||
walk = WALK_ONE_BLOCK_COST;
|
||||
walk = Math.max(JUMP_ONE_BLOCK_COST, WALK_ONE_BLOCK_COST);
|
||||
}
|
||||
walk += context.jumpPenalty;
|
||||
}
|
||||
|
||||
// cracks knuckles
|
||||
|
||||
double totalCost = 0;
|
||||
totalCost += walk;
|
||||
double totalCost = walk;
|
||||
if (hasToPlace) {
|
||||
totalCost += context.placeBlockCost();
|
||||
totalCost += context.placeBlockCost;
|
||||
}
|
||||
if (srcUp2 == null) {
|
||||
srcUp2 = context.get(x, y + 2, z);
|
||||
}
|
||||
totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false); // TODO MAKE ABSOLUTELY SURE we don't need includeFalling here, from the falling check above
|
||||
// start with srcUp2 since we already have its state
|
||||
// includeFalling isn't needed because of the falling check above -- if srcUp3 is falling we will have already exited with COST_INF if we'd actually have to break it
|
||||
totalCost += MovementHelper.getMiningDurationTicks(context, x, y + 2, z, srcUp2, false);
|
||||
if (totalCost >= COST_INF) {
|
||||
return COST_INF;
|
||||
}
|
||||
|
@ -166,8 +162,8 @@ public class MovementAscend extends Movement {
|
|||
|
||||
IBlockState jumpingOnto = BlockStateInterface.get(ctx, positionToPlace);
|
||||
if (!MovementHelper.canWalkOn(ctx, positionToPlace, jumpingOnto)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos anAgainst = positionToPlace.offset(HORIZONTALS[i]);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
BlockPos anAgainst = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
|
||||
if (anAgainst.equals(src)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package baritone.pathing.movement.movements;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.pathing.movement.MovementStatus;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
@ -53,7 +52,7 @@ public class MovementDescend extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
MutableMoveResult result = new MutableMoveResult();
|
||||
cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
|
||||
if (result.y != dest.y) {
|
||||
|
@ -63,11 +62,6 @@ public class MovementDescend extends Movement {
|
|||
}
|
||||
|
||||
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) {
|
||||
Block fromDown = context.get(x, y - 1, z).getBlock();
|
||||
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
double totalCost = 0;
|
||||
IBlockState destDown = context.get(destX, y - 1, destZ);
|
||||
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false);
|
||||
|
@ -83,6 +77,11 @@ public class MovementDescend extends Movement {
|
|||
return;
|
||||
}
|
||||
|
||||
Block fromDown = context.get(x, y - 1, z).getBlock();
|
||||
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
|
||||
return;
|
||||
}
|
||||
|
||||
// A
|
||||
//SA
|
||||
// A
|
||||
|
@ -94,7 +93,7 @@ public class MovementDescend extends Movement {
|
|||
//C, D, etc determine the length of the fall
|
||||
|
||||
IBlockState below = context.get(destX, y - 2, destZ);
|
||||
if (!MovementHelper.canWalkOn(context.bsi(), destX, y - 2, destZ, below)) {
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ, below)) {
|
||||
dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res);
|
||||
return;
|
||||
}
|
||||
|
@ -107,7 +106,7 @@ public class MovementDescend extends Movement {
|
|||
double walk = WALK_OFF_BLOCK_COST;
|
||||
if (fromDown == Blocks.SOUL_SAND) {
|
||||
// use this ratio to apply the soul sand speed penalty to our 0.8 block distance
|
||||
walk = WALK_ONE_OVER_SOUL_SAND_COST;
|
||||
walk *= WALK_ONE_OVER_SOUL_SAND_COST / WALK_ONE_BLOCK_COST;
|
||||
}
|
||||
totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
|
||||
res.x = destX;
|
||||
|
@ -116,66 +115,84 @@ public class MovementDescend extends Movement {
|
|||
res.cost = totalCost;
|
||||
}
|
||||
|
||||
public static void dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
|
||||
public static boolean dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
|
||||
if (frontBreak != 0 && context.get(destX, y + 2, destZ).getBlock() instanceof BlockFalling) {
|
||||
// if frontBreak is 0 we can actually get through this without updating the falling block and making it actually fall
|
||||
// but if frontBreak is nonzero, we're breaking blocks in front, so don't let anything fall through this column,
|
||||
// and potentially replace the water we're going to fall into
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (!MovementHelper.canWalkThrough(context.bsi(), destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
|
||||
return;
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
|
||||
return false;
|
||||
}
|
||||
double costSoFar = 0;
|
||||
int effectiveStartHeight = y;
|
||||
for (int fallHeight = 3; true; fallHeight++) {
|
||||
int newY = y - fallHeight;
|
||||
if (newY < 0) {
|
||||
// when pathing in the end, where you could plausibly fall into the void
|
||||
// this check prevents it from getting the block at y=-1 and crashing
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
IBlockState ontoBlock = context.get(destX, newY, destZ);
|
||||
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak;
|
||||
if (ontoBlock.getBlock() == Blocks.WATER && !MovementHelper.isFlowing(ontoBlock) && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here?
|
||||
int unprotectedFallHeight = fallHeight - (y - effectiveStartHeight); // equal to fallHeight - y + effectiveFallHeight, which is equal to -newY + effectiveFallHeight, which is equal to effectiveFallHeight - newY
|
||||
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[unprotectedFallHeight] + frontBreak + costSoFar;
|
||||
if (ontoBlock.getBlock() == Blocks.WATER && context.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) {
|
||||
// lilypads are canWalkThrough, but we can't end a fall that should be broken by water if it's covered by a lilypad
|
||||
// however, don't return impossible in the lilypad scenario, because we could still jump right on it (water that's below a lilypad is canWalkOn so it works)
|
||||
if (Baritone.settings().assumeWalkOnWater.get()) {
|
||||
return; // TODO fix
|
||||
if (context.assumeWalkOnWater) {
|
||||
return false; // TODO fix
|
||||
}
|
||||
if (MovementHelper.isFlowing(ontoBlock)) {
|
||||
return false; // TODO flowing check required here?
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, newY - 1, destZ)) {
|
||||
// we could punch right through the water into something else
|
||||
return false;
|
||||
}
|
||||
// found a fall into water
|
||||
res.x = destX;
|
||||
res.y = newY;
|
||||
res.z = destZ;
|
||||
res.cost = tentativeCost;// TODO incorporate water swim up cost?
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
if (MovementHelper.canWalkThrough(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
||||
if (unprotectedFallHeight <= 11 && (ontoBlock.getBlock() == Blocks.VINE || ontoBlock.getBlock() == Blocks.LADDER)) {
|
||||
// if fall height is greater than or equal to 11, we don't actually grab on to vines or ladders. the more you know
|
||||
// this effectively "resets" our falling speed
|
||||
costSoFar += FALL_N_BLOCKS_COST[unprotectedFallHeight - 1];// we fall until the top of this block (not including this block)
|
||||
costSoFar += LADDER_DOWN_ONE_COST;
|
||||
effectiveStartHeight = newY;
|
||||
continue;
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi(), destX, newY, destZ, ontoBlock)) {
|
||||
return;
|
||||
if (MovementHelper.canWalkThrough(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
continue;
|
||||
}
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, newY, destZ, ontoBlock)) {
|
||||
return false;
|
||||
}
|
||||
if (MovementHelper.isBottomSlab(ontoBlock)) {
|
||||
return; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
|
||||
return false; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
|
||||
}
|
||||
if (context.hasWaterBucket() && fallHeight <= context.maxFallHeightBucket() + 1) {
|
||||
if (context.hasWaterBucket && unprotectedFallHeight <= context.maxFallHeightBucket + 1) {
|
||||
res.x = destX;
|
||||
res.y = newY + 1;// this is the block we're falling onto, so dest is +1
|
||||
res.z = destZ;
|
||||
res.cost = tentativeCost + context.placeBlockCost();
|
||||
return;
|
||||
res.cost = tentativeCost + context.placeBlockCost;
|
||||
return true;
|
||||
}
|
||||
if (fallHeight <= context.maxFallHeightNoWater() + 1) {
|
||||
if (unprotectedFallHeight <= context.maxFallHeightNoWater + 1) {
|
||||
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
|
||||
res.x = destX;
|
||||
res.y = newY + 1;
|
||||
res.z = destZ;
|
||||
res.cost = tentativeCost;
|
||||
return;
|
||||
return false;
|
||||
} else {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@ 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.pathing.MutableMoveResult;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
@ -38,13 +40,13 @@ public class MovementDiagonal extends Movement {
|
|||
|
||||
private static final double SQRT_2 = Math.sqrt(2);
|
||||
|
||||
public MovementDiagonal(IBaritone baritone, BetterBlockPos start, EnumFacing dir1, EnumFacing dir2) {
|
||||
this(baritone, start, start.offset(dir1), start.offset(dir2), dir2);
|
||||
public MovementDiagonal(IBaritone baritone, BetterBlockPos start, EnumFacing dir1, EnumFacing dir2, int dy) {
|
||||
this(baritone, start, start.offset(dir1), start.offset(dir2), dir2, dy);
|
||||
// super(start, start.offset(dir1).offset(dir2), new BlockPos[]{start.offset(dir1), start.offset(dir1).up(), start.offset(dir2), start.offset(dir2).up(), start.offset(dir1).offset(dir2), start.offset(dir1).offset(dir2).up()}, new BlockPos[]{start.offset(dir1).offset(dir2).down()});
|
||||
}
|
||||
|
||||
private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos dir1, BetterBlockPos dir2, EnumFacing drr2) {
|
||||
this(baritone, start, dir1.offset(drr2), dir1, dir2);
|
||||
private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos dir1, BetterBlockPos dir2, EnumFacing drr2, int dy) {
|
||||
this(baritone, start, dir1.offset(drr2).up(dy), dir1, dir2);
|
||||
}
|
||||
|
||||
private MovementDiagonal(IBaritone baritone, BetterBlockPos start, BetterBlockPos end, BetterBlockPos dir1, BetterBlockPos dir2) {
|
||||
|
@ -52,38 +54,49 @@ public class MovementDiagonal extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
return cost(context, src.x, src.y, src.z, dest.x, dest.z);
|
||||
public double calculateCost(CalculationContext context) {
|
||||
MutableMoveResult result = new MutableMoveResult();
|
||||
cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
|
||||
if (result.y != dest.y) {
|
||||
return COST_INF; // doesn't apply to us, this position is incorrect
|
||||
}
|
||||
return result.cost;
|
||||
}
|
||||
|
||||
public static double cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
|
||||
Block fromDown = context.get(x, y - 1, z).getBlock();
|
||||
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
|
||||
return COST_INF;
|
||||
}
|
||||
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) {
|
||||
IBlockState destInto = context.get(destX, y, destZ);
|
||||
if (!MovementHelper.canWalkThrough(context.bsi(), destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi(), destX, y + 1, destZ)) {
|
||||
return COST_INF;
|
||||
if (!MovementHelper.canWalkThrough(context.bsi, destX, y, destZ, destInto) || !MovementHelper.canWalkThrough(context.bsi, destX, y + 1, destZ)) {
|
||||
return;
|
||||
}
|
||||
IBlockState destWalkOn = context.get(destX, y - 1, destZ);
|
||||
if (!MovementHelper.canWalkOn(context.bsi(), destX, y - 1, destZ, destWalkOn)) {
|
||||
return COST_INF;
|
||||
boolean descend = false;
|
||||
if (!MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
descend = true;
|
||||
if (!context.allowDiagonalDescend || !MovementHelper.canWalkOn(context.bsi, destX, y - 2, destZ) || !MovementHelper.canWalkThrough(context.bsi, destX, y - 1, destZ, destWalkOn)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
double multiplier = WALK_ONE_BLOCK_COST;
|
||||
// For either possible soul sand, that affects half of our walking
|
||||
if (destWalkOn.getBlock() == Blocks.SOUL_SAND) {
|
||||
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
|
||||
} else if (destWalkOn.getBlock() == Blocks.WATER) {
|
||||
multiplier += context.walkOnWaterOnePenalty * SQRT_2;
|
||||
}
|
||||
Block fromDown = context.get(x, y - 1, z).getBlock();
|
||||
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
|
||||
return;
|
||||
}
|
||||
if (fromDown == Blocks.SOUL_SAND) {
|
||||
multiplier += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
|
||||
}
|
||||
Block cuttingOver1 = context.get(x, y - 1, destZ).getBlock();
|
||||
if (cuttingOver1 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver1)) {
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
Block cuttingOver2 = context.get(destX, y - 1, z).getBlock();
|
||||
if (cuttingOver2 == Blocks.MAGMA || MovementHelper.isLava(cuttingOver2)) {
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
IBlockState pb0 = context.get(x, y, destZ);
|
||||
IBlockState pb2 = context.get(destX, y, z);
|
||||
|
@ -92,46 +105,61 @@ public class MovementDiagonal extends Movement {
|
|||
if (optionA != 0 && optionB != 0) {
|
||||
// check these one at a time -- if pb0 and pb2 were nonzero, we already know that (optionA != 0 && optionB != 0)
|
||||
// so no need to check pb1 as well, might as well return early here
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
IBlockState pb1 = context.get(x, y + 1, destZ);
|
||||
optionA += MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
|
||||
if (optionA != 0 && optionB != 0) {
|
||||
// same deal, if pb1 makes optionA nonzero and option B already was nonzero, pb3 can't affect the result
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
IBlockState pb3 = context.get(destX, y + 1, z);
|
||||
if (optionA == 0 && ((MovementHelper.avoidWalkingInto(pb2.getBlock()) && pb2.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb3.getBlock()) && pb3.getBlock() != Blocks.WATER))) {
|
||||
// at this point we're done calculating optionA, so we can check if it's actually possible to edge around in that direction
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
optionB += MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true);
|
||||
if (optionA != 0 && optionB != 0) {
|
||||
// and finally, if the cost is nonzero for both ways to approach this diagonal, it's not possible
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
if (optionB == 0 && ((MovementHelper.avoidWalkingInto(pb0.getBlock()) && pb0.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb1.getBlock()) && pb1.getBlock() != Blocks.WATER))) {
|
||||
// and now that option B is fully calculated, see if we can edge around that way
|
||||
return COST_INF;
|
||||
return;
|
||||
}
|
||||
boolean water = false;
|
||||
if (MovementHelper.isWater(context.getBlock(x, y, z)) || MovementHelper.isWater(destInto.getBlock())) {
|
||||
Block startIn = context.getBlock(x, y, z);
|
||||
if (MovementHelper.isWater(startIn) || MovementHelper.isWater(destInto.getBlock())) {
|
||||
// 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 = context.waterWalkSpeed();
|
||||
multiplier = context.waterWalkSpeed;
|
||||
water = true;
|
||||
}
|
||||
if (optionA != 0 || optionB != 0) {
|
||||
multiplier *= SQRT_2 - 0.001; // TODO tune
|
||||
if (startIn == Blocks.LADDER || startIn == Blocks.VINE) {
|
||||
// edging around doesn't work if doing so would climb a ladder or vine instead of moving sideways
|
||||
return;
|
||||
}
|
||||
if (context.canSprint() && !water) {
|
||||
} else {
|
||||
// only can sprint if not edging around
|
||||
if (context.canSprint && !water) {
|
||||
// If we aren't edging around anything, and we aren't in water
|
||||
// We can sprint =D
|
||||
// Don't check for soul sand, since we can sprint on that too
|
||||
multiplier *= SPRINT_MULTIPLIER;
|
||||
}
|
||||
return multiplier * SQRT_2;
|
||||
}
|
||||
res.cost = multiplier * SQRT_2;
|
||||
if (descend) {
|
||||
res.cost += Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
|
||||
res.y = y - 1;
|
||||
} else {
|
||||
res.y = y;
|
||||
}
|
||||
res.x = destX;
|
||||
res.z = destZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -158,13 +186,13 @@ public class MovementDiagonal extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> toBreak() {
|
||||
public List<BlockPos> toBreak(BlockStateInterface bsi) {
|
||||
if (toBreakCached != null) {
|
||||
return toBreakCached;
|
||||
}
|
||||
List<BlockPos> result = new ArrayList<>();
|
||||
for (int i = 4; i < 6; i++) {
|
||||
if (!MovementHelper.canWalkThrough(ctx, positionsToBreak[i])) {
|
||||
if (!MovementHelper.canWalkThrough(bsi, positionsToBreak[i].x, positionsToBreak[i].y, positionsToBreak[i].z)) {
|
||||
result.add(positionsToBreak[i]);
|
||||
}
|
||||
}
|
||||
|
@ -173,13 +201,13 @@ public class MovementDiagonal extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> toWalkInto() {
|
||||
public List<BlockPos> toWalkInto(BlockStateInterface bsi) {
|
||||
if (toWalkIntoCached == null) {
|
||||
toWalkIntoCached = new ArrayList<>();
|
||||
}
|
||||
List<BlockPos> result = new ArrayList<>();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (!MovementHelper.canWalkThrough(ctx, positionsToBreak[i])) {
|
||||
if (!MovementHelper.canWalkThrough(bsi, positionsToBreak[i].x, positionsToBreak[i].y, positionsToBreak[i].z)) {
|
||||
result.add(positionsToBreak[i]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,22 +43,21 @@ public class MovementDownward extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
return cost(context, src.x, src.y, src.z);
|
||||
}
|
||||
|
||||
public static double cost(CalculationContext context, int x, int y, int z) {
|
||||
if (!MovementHelper.canWalkOn(context.bsi(), x, y - 2, z)) {
|
||||
if (!MovementHelper.canWalkOn(context.bsi, x, y - 2, z)) {
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState d = context.get(x, y - 1, z);
|
||||
Block td = d.getBlock();
|
||||
boolean ladder = td == Blocks.LADDER || td == Blocks.VINE;
|
||||
if (ladder) {
|
||||
IBlockState down = context.get(x, y - 1, z);
|
||||
Block downBlock = down.getBlock();
|
||||
if (downBlock == Blocks.LADDER || downBlock == Blocks.VINE) {
|
||||
return LADDER_DOWN_ONE_COST;
|
||||
} else {
|
||||
// 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, x, y - 1, z, d, false);
|
||||
return FALL_N_BLOCKS_COST[1] + MovementHelper.getMiningDurationTicks(context, x, y - 1, z, down, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package baritone.pathing.movement.movements;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.pathing.movement.MovementStatus;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
@ -31,12 +30,19 @@ import baritone.pathing.movement.MovementHelper;
|
|||
import baritone.pathing.movement.MovementState;
|
||||
import baritone.pathing.movement.MovementState.MovementTarget;
|
||||
import baritone.utils.pathing.MutableMoveResult;
|
||||
import net.minecraft.block.BlockLadder;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.entity.player.InventoryPlayer;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.init.Items;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class MovementFall extends Movement {
|
||||
|
||||
|
@ -48,7 +54,7 @@ public class MovementFall extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
MutableMoveResult result = new MutableMoveResult();
|
||||
MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z, result);
|
||||
if (result.y != dest.y) {
|
||||
|
@ -57,6 +63,12 @@ public class MovementFall extends Movement {
|
|||
return result.cost;
|
||||
}
|
||||
|
||||
private boolean willPlaceBucket() {
|
||||
CalculationContext context = new CalculationContext(baritone);
|
||||
MutableMoveResult result = new MutableMoveResult();
|
||||
return MovementDescend.dynamicFallCost(context, src.x, src.y, src.z, dest.x, dest.z, 0, context.get(dest.x, src.y - 2, dest.z), result);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MovementState updateState(MovementState state) {
|
||||
super.updateState(state);
|
||||
|
@ -67,7 +79,7 @@ public class MovementFall extends Movement {
|
|||
BlockPos playerFeet = ctx.playerFeet();
|
||||
Rotation toDest = RotationUtils.calcRotationFromVec3d(ctx.playerHead(), VecUtils.getBlockPosCenter(dest));
|
||||
Rotation targetRotation = null;
|
||||
if (!MovementHelper.isWater(ctx, dest) && src.getY() - dest.getY() > Baritone.settings().maxFallHeightNoWater.get() && !playerFeet.equals(dest)) {
|
||||
if (!MovementHelper.isWater(ctx, dest) && willPlaceBucket() && !playerFeet.equals(dest)) {
|
||||
if (!InventoryPlayer.isHotbar(ctx.player().inventory.getSlotFor(STACK_BUCKET_WATER)) || ctx.world().provider.isNether()) {
|
||||
return state.setStatus(MovementStatus.UNREACHABLE);
|
||||
}
|
||||
|
@ -78,7 +90,7 @@ public class MovementFall extends Movement {
|
|||
targetRotation = new Rotation(toDest.getYaw(), 90.0F);
|
||||
|
||||
RayTraceResult trace = ctx.objectMouseOver();
|
||||
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && ctx.player().rotationPitch > 89.0F) {
|
||||
if (trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK && (trace.getBlockPos().equals(dest) || trace.getBlockPos().equals(dest.down()))) {
|
||||
state.setInput(Input.CLICK_RIGHT, true);
|
||||
}
|
||||
}
|
||||
|
@ -107,12 +119,40 @@ public class MovementFall extends Movement {
|
|||
}
|
||||
}
|
||||
Vec3d destCenter = VecUtils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder)
|
||||
if (Math.abs(ctx.player().posX - destCenter.x) > 0.15 || Math.abs(ctx.player().posZ - destCenter.z) > 0.15) {
|
||||
if (Math.abs(ctx.player().posX + ctx.player().motionX - destCenter.x) > 0.1 || Math.abs(ctx.player().posZ + ctx.player().motionZ - destCenter.z) > 0.1) {
|
||||
if (!ctx.player().onGround && Math.abs(ctx.player().motionY) > 0.4) {
|
||||
state.setInput(Input.SNEAK, true);
|
||||
}
|
||||
state.setInput(Input.MOVE_FORWARD, true);
|
||||
}
|
||||
Vec3i avoid = Optional.ofNullable(avoid()).map(EnumFacing::getDirectionVec).orElse(null);
|
||||
if (avoid == null) {
|
||||
avoid = src.subtract(dest);
|
||||
} else {
|
||||
double dist = Math.abs(avoid.getX() * (destCenter.x - avoid.getX() / 2.0 - ctx.player().posX)) + Math.abs(avoid.getZ() * (destCenter.z - avoid.getZ() / 2.0 - ctx.player().posZ));
|
||||
if (dist < 0.6) {
|
||||
state.setInput(Input.MOVE_FORWARD, true);
|
||||
} else {
|
||||
state.setInput(Input.SNEAK, false);
|
||||
}
|
||||
}
|
||||
if (targetRotation == null) {
|
||||
Vec3d destCenterOffset = new Vec3d(destCenter.x + 0.125 * avoid.getX(), destCenter.y, destCenter.z + 0.125 * avoid.getZ());
|
||||
state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(ctx.playerHead(), destCenterOffset), false));
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
private EnumFacing avoid() {
|
||||
for (int i = 0; i < 15; i++) {
|
||||
IBlockState state = ctx.world().getBlockState(ctx.playerFeet().down(i));
|
||||
if (state.getBlock() == Blocks.LADDER) {
|
||||
return state.getValue(BlockLadder.FACING);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean safeToCancel(MovementState state) {
|
||||
// if we haven't started walking off the edge yet, or if we're in the process of breaking blocks before doing the fall
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package baritone.pathing.movement.movements;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.pathing.movement.MovementStatus;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
|
@ -30,7 +29,6 @@ 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.pathing.MutableMoveResult;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockStairs;
|
||||
|
@ -41,11 +39,8 @@ import net.minecraft.util.math.BlockPos;
|
|||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class MovementParkour extends Movement {
|
||||
|
||||
private static final EnumFacing[] HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST, EnumFacing.DOWN};
|
||||
private static final BetterBlockPos[] EMPTY = new BetterBlockPos[]{};
|
||||
|
||||
private final EnumFacing direction;
|
||||
|
@ -65,24 +60,25 @@ public class MovementParkour extends Movement {
|
|||
}
|
||||
|
||||
public static void cost(CalculationContext context, int x, int y, int z, EnumFacing dir, MutableMoveResult res) {
|
||||
if (!Baritone.settings().allowParkour.get()) {
|
||||
if (!context.allowParkour) {
|
||||
return;
|
||||
}
|
||||
IBlockState standingOn = context.get(x, y - 1, z);
|
||||
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof BlockStairs || MovementHelper.isBottomSlab(standingOn)) {
|
||||
return;
|
||||
}
|
||||
int xDiff = dir.getXOffset();
|
||||
int zDiff = dir.getZOffset();
|
||||
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff);
|
||||
if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks
|
||||
return;
|
||||
}
|
||||
if (MovementHelper.canWalkOn(context.bsi(), x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
|
||||
if (y == 256 && !context.allowJumpAt256) {
|
||||
return;
|
||||
}
|
||||
|
||||
int xDiff = dir.getXOffset();
|
||||
int zDiff = dir.getZOffset();
|
||||
if (!MovementHelper.fullyPassable(context, x + xDiff, y, z + zDiff)) {
|
||||
// most common case at the top -- the adjacent block isn't air
|
||||
return;
|
||||
}
|
||||
IBlockState adj = context.get(x + xDiff, y - 1, z + zDiff);
|
||||
if (MovementHelper.canWalkOn(context.bsi, x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
|
||||
// second most common case -- we could just traverse not parkour
|
||||
return;
|
||||
}
|
||||
if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks
|
||||
return;
|
||||
}
|
||||
if (!MovementHelper.fullyPassable(context, x + xDiff, y + 1, z + zDiff)) {
|
||||
|
@ -94,11 +90,15 @@ public class MovementParkour extends Movement {
|
|||
if (!MovementHelper.fullyPassable(context, x, y + 2, z)) {
|
||||
return;
|
||||
}
|
||||
IBlockState standingOn = context.get(x, y - 1, z);
|
||||
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || standingOn.getBlock() instanceof BlockStairs || MovementHelper.isBottomSlab(standingOn)) {
|
||||
return;
|
||||
}
|
||||
int maxJump;
|
||||
if (standingOn.getBlock() == Blocks.SOUL_SAND) {
|
||||
maxJump = 2; // 1 block gap
|
||||
} else {
|
||||
if (context.canSprint()) {
|
||||
if (context.canSprint) {
|
||||
maxJump = 4;
|
||||
} else {
|
||||
maxJump = 3;
|
||||
|
@ -111,44 +111,41 @@ public class MovementParkour extends Movement {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (MovementHelper.canWalkOn(context.bsi(), x + xDiff * i, y - 1, z + zDiff * i)) {
|
||||
if (MovementHelper.canWalkOn(context.bsi, x + xDiff * i, y - 1, z + zDiff * i)) {
|
||||
res.x = x + xDiff * i;
|
||||
res.y = y;
|
||||
res.z = z + zDiff * i;
|
||||
res.cost = costFromJumpDistance(i);
|
||||
res.cost = costFromJumpDistance(i) + context.jumpPenalty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (maxJump != 4) {
|
||||
return;
|
||||
}
|
||||
if (!Baritone.settings().allowParkourPlace.get()) {
|
||||
return;
|
||||
}
|
||||
if (!Baritone.settings().allowPlace.get()) {
|
||||
Helper.HELPER.logDirect("allowParkourPlace enabled but allowPlace disabled?");
|
||||
if (!context.allowParkourPlace) {
|
||||
return;
|
||||
}
|
||||
int destX = x + 4 * xDiff;
|
||||
int destZ = z + 4 * zDiff;
|
||||
IBlockState toPlace = context.get(destX, y - 1, destZ);
|
||||
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
|
||||
return;
|
||||
}
|
||||
if (toPlace.getBlock() != Blocks.AIR && !MovementHelper.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace, context.world())) {
|
||||
IBlockState toReplace = context.get(destX, y - 1, destZ);
|
||||
if (!MovementHelper.isReplacable(destX, y - 1, destZ, toReplace, context.bsi)) {
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
|
||||
int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset();
|
||||
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset();
|
||||
if (againstX == x + xDiff * 3 && againstZ == z + zDiff * 3) { // we can't turn around that fast
|
||||
continue;
|
||||
}
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y - 1, againstZ)) {
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) {
|
||||
res.x = destX;
|
||||
res.y = y;
|
||||
res.z = destZ;
|
||||
res.cost = costFromJumpDistance(4) + context.placeBlockCost();
|
||||
res.cost = costFromJumpDistance(4) + context.placeBlockCost + context.jumpPenalty;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -169,7 +166,7 @@ public class MovementParkour extends Movement {
|
|||
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
MutableMoveResult res = new MutableMoveResult();
|
||||
cost(context, src.x, src.y, src.z, direction, res);
|
||||
if (res.x != dest.x || res.z != dest.z) {
|
||||
|
@ -215,7 +212,7 @@ public class MovementParkour extends Movement {
|
|||
|
||||
if (!MovementHelper.canWalkOn(ctx, dest.down()) && !ctx.player().onGround) {
|
||||
BlockPos positionToPlace = dest.down();
|
||||
for (int i = 0; i < 5; i++) {
|
||||
for (int i = 4; i >= 0; i--) { // go in the opposite order to check DOWN before all horizontals -- down is preferable because you don't have to look to the side while in midair, which could mess up the trajectory
|
||||
BlockPos against1 = positionToPlace.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
|
||||
if (against1.up().equals(src.offset(direction, 3))) { // we can't turn around that fast
|
||||
continue;
|
||||
|
@ -231,16 +228,17 @@ public class MovementParkour extends Movement {
|
|||
RayTraceResult res = RayTraceUtils.rayTraceTowards(ctx.player(), place, ctx.playerController().getBlockReachDistance());
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ctx.getSelectedBlock().ifPresent(selectedBlock -> {
|
||||
EnumFacing side = ctx.objectMouseOver().sideHit;
|
||||
if (Objects.equals(selectedBlock, against1) && selectedBlock.offset(side).equals(dest.down())) {
|
||||
if (MovementHelper.canPlaceAgainst(ctx, selectedBlock) && selectedBlock.offset(side).equals(dest.down())) {
|
||||
state.setInput(Input.CLICK_RIGHT, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dist == 3) { // this is a 2 block gap, dest = src + direction * 3
|
||||
double xDiff = (src.x + 0.5) - ctx.player().posX;
|
||||
double zDiff = (src.z + 0.5) - ctx.player().posZ;
|
||||
|
|
|
@ -42,38 +42,44 @@ public class MovementPillar extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
return cost(context, src.x, src.y, src.z);
|
||||
}
|
||||
|
||||
public static double cost(CalculationContext context, int x, int y, int z) {
|
||||
Block fromDown = context.get(x, y, z).getBlock();
|
||||
boolean ladder = fromDown instanceof BlockLadder || fromDown instanceof BlockVine;
|
||||
IBlockState fromDownDown = context.get(x, y - 1, z);
|
||||
Block from = context.get(x, y, z).getBlock();
|
||||
boolean ladder = from == Blocks.LADDER || from == Blocks.VINE;
|
||||
IBlockState fromDown = context.get(x, y - 1, z);
|
||||
if (!ladder) {
|
||||
if (fromDownDown.getBlock() instanceof BlockLadder || fromDownDown.getBlock() instanceof BlockVine) {
|
||||
return COST_INF;
|
||||
if (fromDown.getBlock() == Blocks.LADDER || fromDown.getBlock() == Blocks.VINE) {
|
||||
return COST_INF; // can't pillar from a ladder or vine onto something that isn't also climbable
|
||||
}
|
||||
if (fromDownDown.getBlock() instanceof BlockSlab && !((BlockSlab) fromDownDown.getBlock()).isDouble() && fromDownDown.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
|
||||
if (fromDown.getBlock() instanceof BlockSlab && !((BlockSlab) fromDown.getBlock()).isDouble() && fromDown.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM) {
|
||||
return COST_INF; // can't pillar up from a bottom slab onto a non ladder
|
||||
}
|
||||
}
|
||||
if (fromDown instanceof BlockVine && !hasAgainst(context, x, y, z)) {
|
||||
if (from == Blocks.VINE && !hasAgainst(context, x, y, z)) { // TODO this vine can't be climbed, but we could place a pillar still since vines are replacable, no? perhaps the pillar jump would be impossible because of the slowdown actually.
|
||||
return COST_INF;
|
||||
}
|
||||
IBlockState toBreak = context.get(x, y + 2, z);
|
||||
Block toBreakBlock = toBreak.getBlock();
|
||||
if (toBreakBlock instanceof BlockFenceGate) {
|
||||
if (toBreakBlock instanceof BlockFenceGate) { // see issue #172
|
||||
return COST_INF;
|
||||
}
|
||||
Block srcUp = null;
|
||||
if (MovementHelper.isWater(toBreakBlock) && MovementHelper.isWater(fromDown)) {
|
||||
if (MovementHelper.isWater(toBreakBlock) && MovementHelper.isWater(from)) { // TODO should this also be allowed if toBreakBlock is air?
|
||||
srcUp = context.get(x, y + 1, z).getBlock();
|
||||
if (MovementHelper.isWater(srcUp)) {
|
||||
return LADDER_UP_ONE_COST;
|
||||
return LADDER_UP_ONE_COST; // allow ascending pillars of water, but only if we're already in one
|
||||
}
|
||||
}
|
||||
if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) {
|
||||
if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) { // we need to place a block where we started to jump on it
|
||||
return COST_INF;
|
||||
}
|
||||
if (from instanceof BlockLiquid || (fromDown.getBlock() instanceof BlockLiquid && context.assumeWalkOnWater)) {
|
||||
// otherwise, if we're standing in water, we cannot pillar
|
||||
// if we're standing on water and assumeWalkOnWater is true, we cannot pillar
|
||||
// if we're standing on water and assumeWalkOnWater is false, we must have ascended to here, or sneak backplaced, so it is possible to pillar again
|
||||
return COST_INF;
|
||||
}
|
||||
double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true);
|
||||
|
@ -81,10 +87,10 @@ public class MovementPillar extends Movement {
|
|||
return COST_INF;
|
||||
}
|
||||
if (hardness != 0) {
|
||||
if (toBreakBlock instanceof BlockLadder || toBreakBlock instanceof BlockVine) {
|
||||
if (toBreakBlock == Blocks.LADDER || toBreakBlock == Blocks.VINE) {
|
||||
hardness = 0; // we won't actually need to break the ladder / vine because we're going to use it
|
||||
} else {
|
||||
IBlockState check = context.get(x, y + 3, z);
|
||||
IBlockState check = context.get(x, y + 3, z); // the block on top of the one we're going to break, could it fall on us?
|
||||
if (check.getBlock() instanceof BlockFalling) {
|
||||
// see MovementAscend's identical check for breaking a falling block above our head
|
||||
if (srcUp == null) {
|
||||
|
@ -103,13 +109,10 @@ public class MovementPillar extends Movement {
|
|||
//}
|
||||
}
|
||||
}
|
||||
if (fromDown instanceof BlockLiquid || fromDownDown.getBlock() instanceof BlockLiquid) {//can't pillar on water or in water
|
||||
return COST_INF;
|
||||
}
|
||||
if (ladder) {
|
||||
return LADDER_UP_ONE_COST + hardness * 5;
|
||||
} else {
|
||||
return JUMP_ONE_BLOCK_COST + context.placeBlockCost() + hardness;
|
||||
return JUMP_ONE_BLOCK_COST + context.placeBlockCost + context.jumpPenalty + hardness;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -156,8 +159,8 @@ public class MovementPillar extends Movement {
|
|||
}
|
||||
return state;
|
||||
}
|
||||
boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine;
|
||||
boolean vine = fromDown.getBlock() instanceof BlockVine;
|
||||
boolean ladder = fromDown.getBlock() == Blocks.LADDER || fromDown.getBlock() == Blocks.VINE;
|
||||
boolean vine = fromDown.getBlock() == Blocks.VINE;
|
||||
Rotation rotation = RotationUtils.calcRotationFromVec3d(ctx.player().getPositionEyes(1.0F),
|
||||
VecUtils.getBlockPosCenter(positionToPlace),
|
||||
new Rotation(ctx.player().rotationYaw, ctx.player().rotationPitch));
|
||||
|
|
|
@ -30,7 +30,10 @@ import baritone.pathing.movement.Movement;
|
|||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.movement.MovementState;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.block.*;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockDoor;
|
||||
import net.minecraft.block.BlockFenceGate;
|
||||
import net.minecraft.block.BlockSlab;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
@ -57,7 +60,7 @@ public class MovementTraverse extends Movement {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected double calculateCost(CalculationContext context) {
|
||||
public double calculateCost(CalculationContext context) {
|
||||
return cost(context, src.x, src.y, src.z, dest.x, dest.z);
|
||||
}
|
||||
|
||||
|
@ -66,27 +69,29 @@ public class MovementTraverse extends Movement {
|
|||
IBlockState pb1 = context.get(destX, y, destZ);
|
||||
IBlockState destOn = context.get(destX, y - 1, destZ);
|
||||
Block srcDown = context.getBlock(x, y - 1, z);
|
||||
if (MovementHelper.canWalkOn(context.bsi(), destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
|
||||
if (MovementHelper.canWalkOn(context.bsi, destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
|
||||
double WC = WALK_ONE_BLOCK_COST;
|
||||
boolean water = false;
|
||||
if (MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock())) {
|
||||
WC = context.waterWalkSpeed();
|
||||
WC = context.waterWalkSpeed;
|
||||
water = true;
|
||||
} else {
|
||||
if (destOn.getBlock() == Blocks.SOUL_SAND) {
|
||||
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
|
||||
} else if (destOn.getBlock() == Blocks.WATER) {
|
||||
WC += context.walkOnWaterOnePenalty;
|
||||
}
|
||||
if (srcDown == Blocks.SOUL_SAND) {
|
||||
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
|
||||
}
|
||||
}
|
||||
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true);
|
||||
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
|
||||
if (hardness1 >= COST_INF) {
|
||||
return COST_INF;
|
||||
}
|
||||
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
|
||||
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true); // only include falling on the upper block to break
|
||||
if (hardness1 == 0 && hardness2 == 0) {
|
||||
if (!water && context.canSprint()) {
|
||||
if (!water && context.canSprint) {
|
||||
// If there's nothing in the way, and this isn't water, and we aren't sneak placing
|
||||
// We can sprint =D
|
||||
// Don't check for soul sand, since we can sprint on that too
|
||||
|
@ -103,42 +108,43 @@ public class MovementTraverse extends Movement {
|
|||
if (srcDown == Blocks.LADDER || srcDown == Blocks.VINE) {
|
||||
return COST_INF;
|
||||
}
|
||||
if (destOn.getBlock().equals(Blocks.AIR) || MovementHelper.isReplacable(destX, y - 1, destZ, destOn, context.world())) {
|
||||
if (MovementHelper.isReplacable(destX, y - 1, destZ, destOn, context.bsi)) {
|
||||
boolean throughWater = MovementHelper.isWater(pb0.getBlock()) || MovementHelper.isWater(pb1.getBlock());
|
||||
if (MovementHelper.isWater(destOn.getBlock()) && throughWater) {
|
||||
// this happens when assume walk on water is true and this is a traverse in water, which isn't allowed
|
||||
return COST_INF;
|
||||
}
|
||||
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
|
||||
return COST_INF;
|
||||
}
|
||||
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb0, false);
|
||||
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
|
||||
if (hardness1 >= COST_INF) {
|
||||
return COST_INF;
|
||||
}
|
||||
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb1, true);
|
||||
|
||||
double WC = throughWater ? context.waterWalkSpeed() : WALK_ONE_BLOCK_COST;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int againstX = destX + HORIZONTALS[i].getXOffset();
|
||||
int againstZ = destZ + HORIZONTALS[i].getZOffset();
|
||||
if (againstX == x && againstZ == z) {
|
||||
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb0, true); // only include falling on the upper block to break
|
||||
double WC = throughWater ? context.waterWalkSpeed : WALK_ONE_BLOCK_COST;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
|
||||
int againstY = y - 1 + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getYOffset();
|
||||
int againstZ = destZ + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getZOffset();
|
||||
if (againstX == x && againstZ == z) { // this would be a backplace
|
||||
continue;
|
||||
}
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi(), againstX, y - 1, againstZ)) {
|
||||
return WC + context.placeBlockCost() + hardness1 + hardness2;
|
||||
if (MovementHelper.canPlaceAgainst(context.bsi, againstX, againstY, againstZ)) { // found a side place option
|
||||
return WC + context.placeBlockCost + hardness1 + hardness2;
|
||||
}
|
||||
}
|
||||
// now that we've checked all possible directions to side place, we actually need to backplace
|
||||
if (srcDown == Blocks.SOUL_SAND || (srcDown instanceof BlockSlab && !((BlockSlab) srcDown).isDouble())) {
|
||||
return COST_INF; // can't sneak and backplace against soul sand or half slabs =/
|
||||
}
|
||||
if (srcDown == Blocks.FLOWING_WATER || srcDown == Blocks.WATER) {
|
||||
return COST_INF; // this is obviously impossible
|
||||
}
|
||||
WC = WC * SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST;//since we are placing, we are sneaking
|
||||
return WC + context.placeBlockCost() + hardness1 + hardness2;
|
||||
WC = WC * (SNEAK_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST);//since we are sneak backplacing, we are sneaking lol
|
||||
return WC + context.placeBlockCost + hardness1 + hardness2;
|
||||
}
|
||||
return COST_INF;
|
||||
// Out.log("Can't walk on " + Baritone.get(positionsToPlace[0]).getBlock());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -180,7 +186,7 @@ public class MovementTraverse extends Movement {
|
|||
state.setInput(Input.SNEAK, false);
|
||||
|
||||
Block fd = BlockStateInterface.get(ctx, src.down()).getBlock();
|
||||
boolean ladder = fd instanceof BlockLadder || fd instanceof BlockVine;
|
||||
boolean ladder = fd == Blocks.LADDER || fd == Blocks.VINE;
|
||||
IBlockState pb0 = BlockStateInterface.get(ctx, positionsToBreak[0]);
|
||||
IBlockState pb1 = BlockStateInterface.get(ctx, positionsToBreak[1]);
|
||||
|
||||
|
@ -233,7 +239,7 @@ public class MovementTraverse extends Movement {
|
|||
state.setInput(Input.SPRINT, true);
|
||||
}
|
||||
Block destDown = BlockStateInterface.get(ctx, dest.down()).getBlock();
|
||||
if (whereAmI.getY() != dest.getY() && ladder && (destDown instanceof BlockVine || destDown instanceof BlockLadder)) {
|
||||
if (whereAmI.getY() != dest.getY() && ladder && (destDown == Blocks.VINE || destDown == Blocks.LADDER)) {
|
||||
new MovementPillar(baritone, dest.down(), dest).updateState(state); // i'm sorry
|
||||
return state;
|
||||
}
|
||||
|
@ -241,8 +247,8 @@ public class MovementTraverse extends Movement {
|
|||
return state;
|
||||
} else {
|
||||
wasTheBridgeBlockAlwaysThere = false;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
BlockPos against1 = dest.offset(HORIZONTALS[i]);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
BlockPos against1 = dest.offset(HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i]);
|
||||
if (against1.equals(src)) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,12 @@ import baritone.api.utils.input.Input;
|
|||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.Movement;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.movement.movements.*;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.Helper;
|
||||
import net.minecraft.block.BlockLiquid;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
@ -108,7 +110,6 @@ public class PathExecutor implements IPathExecutor, Helper {
|
|||
return false;
|
||||
}
|
||||
|
||||
//System.out.println("Should be at " + whereShouldIBe + " actually am at " + whereAmI);
|
||||
if (!Blocks.AIR.equals(BlockStateInterface.getBlock(ctx, whereAmI.down()))) {//do not skip if standing on air, because our position isn't stable to skip
|
||||
for (int i = 0; i < pathPosition - 1 && 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))) {
|
||||
|
@ -186,22 +187,23 @@ public class PathExecutor implements IPathExecutor, Helper {
|
|||
}
|
||||
}*/
|
||||
//long start = System.nanoTime() / 1000000L;
|
||||
BlockStateInterface bsi = new BlockStateInterface(ctx);
|
||||
for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
|
||||
if (i < 0 || i >= path.movements().size()) {
|
||||
continue;
|
||||
}
|
||||
IMovement m = path.movements().get(i);
|
||||
HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak());
|
||||
HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace());
|
||||
HashSet<BlockPos> prevWalkInto = new HashSet<>(m.toWalkInto());
|
||||
Movement m = (Movement) path.movements().get(i);
|
||||
HashSet<BlockPos> prevBreak = new HashSet<>(m.toBreak(bsi));
|
||||
HashSet<BlockPos> prevPlace = new HashSet<>(m.toPlace(bsi));
|
||||
HashSet<BlockPos> prevWalkInto = new HashSet<>(m.toWalkInto(bsi));
|
||||
m.resetBlockCache();
|
||||
if (!prevBreak.equals(new HashSet<>(m.toBreak()))) {
|
||||
if (!prevBreak.equals(new HashSet<>(m.toBreak(bsi)))) {
|
||||
recalcBP = true;
|
||||
}
|
||||
if (!prevPlace.equals(new HashSet<>(m.toPlace()))) {
|
||||
if (!prevPlace.equals(new HashSet<>(m.toPlace(bsi)))) {
|
||||
recalcBP = true;
|
||||
}
|
||||
if (!prevWalkInto.equals(new HashSet<>(m.toWalkInto()))) {
|
||||
if (!prevWalkInto.equals(new HashSet<>(m.toWalkInto(bsi)))) {
|
||||
recalcBP = true;
|
||||
}
|
||||
}
|
||||
|
@ -210,9 +212,10 @@ public class PathExecutor implements IPathExecutor, Helper {
|
|||
HashSet<BlockPos> newPlace = new HashSet<>();
|
||||
HashSet<BlockPos> newWalkInto = new HashSet<>();
|
||||
for (int i = pathPosition; i < path.movements().size(); i++) {
|
||||
newBreak.addAll(path.movements().get(i).toBreak());
|
||||
newPlace.addAll(path.movements().get(i).toPlace());
|
||||
newWalkInto.addAll(path.movements().get(i).toWalkInto());
|
||||
Movement movement = (Movement) path.movements().get(i);
|
||||
newBreak.addAll(movement.toBreak(bsi));
|
||||
newPlace.addAll(movement.toPlace(bsi));
|
||||
newWalkInto.addAll(movement.toWalkInto(bsi));
|
||||
}
|
||||
toBreak = newBreak;
|
||||
toPlace = newPlace;
|
||||
|
@ -344,27 +347,41 @@ public class PathExecutor implements IPathExecutor, Helper {
|
|||
|
||||
/**
|
||||
* Regardless of current path position, snap to the current player feet if possible
|
||||
*
|
||||
* @return Whether or not it was possible to snap to the current player feet
|
||||
*/
|
||||
public boolean snipsnapifpossible() {
|
||||
if (!ctx.player().onGround && !(ctx.world().getBlockState(ctx.playerFeet()).getBlock() instanceof BlockLiquid)) {
|
||||
// if we're falling in the air, and not in water, don't splice
|
||||
return false;
|
||||
} else {
|
||||
// we are either onGround or in liquid
|
||||
if (ctx.player().motionY < -0.1) {
|
||||
// if we are strictly moving downwards (not stationary)
|
||||
// we could be falling through water, which could be unsafe to splice
|
||||
return false; // so don't
|
||||
}
|
||||
}
|
||||
int index = path.positions().indexOf(ctx.playerFeet());
|
||||
if (index == -1) {
|
||||
return false;
|
||||
}
|
||||
pathPosition = index;
|
||||
pathPosition = index; // jump directly to current position
|
||||
clearKeys();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void sprintIfRequested() {
|
||||
// first and foremost, if allowSprint is off, or if we don't have enough hunger, don't try and sprint
|
||||
if (!new CalculationContext(behavior.baritone).canSprint()) {
|
||||
if (!new CalculationContext(behavior.baritone).canSprint) {
|
||||
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false);
|
||||
ctx.player().setSprinting(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// if the movement requested sprinting, then we're done
|
||||
if (behavior.baritone.getInputOverrideHandler().isInputForcedDown(mc.gameSettings.keyBindSprint)) {
|
||||
if (behavior.baritone.getInputOverrideHandler().isInputForcedDown(Input.SPRINT)) {
|
||||
behavior.baritone.getInputOverrideHandler().setInputForceState(Input.SPRINT, false);
|
||||
if (!ctx.player().isSprinting()) {
|
||||
ctx.player().setSprinting(true);
|
||||
}
|
||||
|
|
|
@ -62,13 +62,15 @@ public class SplicedPath extends PathBase {
|
|||
return numNodes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length() {
|
||||
return path.size();
|
||||
}
|
||||
|
||||
public static Optional<SplicedPath> trySplice(IPath first, IPath second, boolean allowOverlapCutoff) {
|
||||
if (second == null || first == null) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (!Objects.equals(first.getGoal(), second.getGoal())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
if (!first.getDest().equals(second.getSrc())) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -77,6 +79,7 @@ public class SplicedPath extends PathBase {
|
|||
for (int i = 0; i < first.length() - 1; i++) { // overlap in the very last element is fine (and required) so only go up to first.length() - 1
|
||||
if (secondPos.contains(first.positions().get(i))) {
|
||||
firstPositionInSecond = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (firstPositionInSecond != -1) {
|
||||
|
|
|
@ -52,8 +52,10 @@ public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomG
|
|||
@Override
|
||||
public void setGoal(Goal goal) {
|
||||
this.goal = goal;
|
||||
if (this.state == State.NONE) {
|
||||
this.state = State.GOAL_SET;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void path() {
|
||||
|
@ -74,7 +76,7 @@ public class CustomGoalProcess extends BaritoneProcessHelper implements ICustomG
|
|||
public PathingCommand onTick(boolean calcFailed, boolean isSafeToCancel) {
|
||||
switch (this.state) {
|
||||
case GOAL_SET:
|
||||
if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal(), this.goal)) {
|
||||
if (!baritone.getPathingBehavior().isPathing() && Objects.equals(baritone.getPathingBehavior().getGoal() + "", this.goal + "")) {
|
||||
this.state = State.NONE;
|
||||
}
|
||||
return new PathingCommand(this.goal, PathingCommandType.CANCEL_AND_SET_GOAL);
|
||||
|
|
|
@ -57,7 +57,6 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
|
|||
}
|
||||
|
||||
private Goal towards(Entity following) {
|
||||
// lol this is trashy but it works
|
||||
BlockPos pos;
|
||||
if (Baritone.settings().followOffsetDistance.get() == 0) {
|
||||
pos = new BlockPos(following);
|
||||
|
@ -79,7 +78,7 @@ public final class FollowProcess extends BaritoneProcessHelper implements IFollo
|
|||
if (entity.equals(ctx.player())) {
|
||||
return false;
|
||||
}
|
||||
return ctx.world().loadedEntityList.contains(entity) || ctx.world().playerEntities.contains(entity);
|
||||
return ctx.world().loadedEntityList.contains(entity);
|
||||
}
|
||||
|
||||
private void scanWorld() {
|
||||
|
|
|
@ -21,19 +21,27 @@ import baritone.Baritone;
|
|||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.pathing.goals.GoalComposite;
|
||||
import baritone.api.pathing.goals.GoalGetToBlock;
|
||||
import baritone.api.pathing.goals.GoalTwoBlocks;
|
||||
import baritone.api.process.IGetToBlockProcess;
|
||||
import baritone.api.process.PathingCommand;
|
||||
import baritone.api.process.PathingCommandType;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.api.utils.RotationUtils;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.utils.BaritoneProcessHelper;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.init.Blocks;
|
||||
import net.minecraft.inventory.ContainerPlayer;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBlockProcess {
|
||||
|
||||
private Block gettingTo;
|
||||
private List<BlockPos> knownLocations;
|
||||
|
||||
|
@ -45,8 +53,8 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
|
|||
|
||||
@Override
|
||||
public void getToBlock(Block block) {
|
||||
onLostControl();
|
||||
gettingTo = block;
|
||||
knownLocations = null;
|
||||
rescan(new ArrayList<>(), new CalculationContext(baritone));
|
||||
}
|
||||
|
||||
|
@ -77,13 +85,20 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
|
|||
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get();
|
||||
if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain
|
||||
List<BlockPos> current = new ArrayList<>(knownLocations);
|
||||
CalculationContext context = new CalculationContext(baritone);
|
||||
CalculationContext context = new CalculationContext(baritone, true);
|
||||
Baritone.getExecutor().execute(() -> rescan(current, context));
|
||||
}
|
||||
Goal goal = new GoalComposite(knownLocations.stream().map(GoalGetToBlock::new).toArray(Goal[]::new));
|
||||
if (goal.isInGoal(ctx.playerFeet())) {
|
||||
Goal goal = new GoalComposite(knownLocations.stream().map(this::createGoal).toArray(Goal[]::new));
|
||||
if (goal.isInGoal(ctx.playerFeet()) && isSafeToCancel) {
|
||||
// we're there
|
||||
if (rightClickOnArrival(gettingTo)) {
|
||||
if (rightClick()) {
|
||||
onLostControl();
|
||||
}
|
||||
} else {
|
||||
onLostControl();
|
||||
}
|
||||
}
|
||||
return new PathingCommand(goal, PathingCommandType.REVALIDATE_GOAL_AND_PATH);
|
||||
}
|
||||
|
||||
|
@ -91,6 +106,7 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
|
|||
public void onLostControl() {
|
||||
gettingTo = null;
|
||||
knownLocations = null;
|
||||
baritone.getInputOverrideHandler().clearAllKeys();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,4 +117,41 @@ public class GetToBlockProcess extends BaritoneProcessHelper implements IGetToBl
|
|||
private void rescan(List<BlockPos> known, CalculationContext context) {
|
||||
knownLocations = MineProcess.searchWorld(context, Collections.singletonList(gettingTo), 64, known);
|
||||
}
|
||||
|
||||
private Goal createGoal(BlockPos pos) {
|
||||
return walkIntoInsteadOfAdjacent(gettingTo) ? new GoalTwoBlocks(pos) : new GoalGetToBlock(pos);
|
||||
}
|
||||
|
||||
private boolean rightClick() {
|
||||
for (BlockPos pos : knownLocations) {
|
||||
Optional<Rotation> reachable = RotationUtils.reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
|
||||
if (reachable.isPresent()) {
|
||||
baritone.getLookBehavior().updateTarget(reachable.get(), true);
|
||||
if (knownLocations.contains(ctx.getSelectedBlock().orElse(null))) {
|
||||
baritone.getInputOverrideHandler().setInputForceState(Input.CLICK_RIGHT, true); // TODO find some way to right click even if we're in an ESC menu
|
||||
System.out.println(ctx.player().openContainer);
|
||||
if (!(ctx.player().openContainer instanceof ContainerPlayer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false; // trying to right click, will do it next tick or so
|
||||
}
|
||||
}
|
||||
logDirect("Arrived but failed to right click open");
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean walkIntoInsteadOfAdjacent(Block block) {
|
||||
if (!Baritone.settings().enterPortal.get()) {
|
||||
return false;
|
||||
}
|
||||
return block == Blocks.PORTAL;
|
||||
}
|
||||
|
||||
private boolean rightClickOnArrival(Block block) {
|
||||
if (!Baritone.settings().rightClickContainerOnArrival.get()) {
|
||||
return false;
|
||||
}
|
||||
return block == Blocks.CRAFTING_TABLE || block == Blocks.FURNACE || block == Blocks.ENDER_CHEST || block == Blocks.CHEST || block == Blocks.TRAPPED_CHEST;
|
||||
}
|
||||
}
|
|
@ -39,7 +39,6 @@ import net.minecraft.item.Item;
|
|||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
@ -89,7 +88,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
|||
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get();
|
||||
if (mineGoalUpdateInterval != 0 && tickCount++ % mineGoalUpdateInterval == 0) { // big brain
|
||||
List<BlockPos> curr = new ArrayList<>(knownOreLocations);
|
||||
CalculationContext context = new CalculationContext(baritone);
|
||||
CalculationContext context = new CalculationContext(baritone, true);
|
||||
Baritone.getExecutor().execute(() -> rescan(curr, context));
|
||||
}
|
||||
if (Baritone.settings().legitMine.get()) {
|
||||
|
@ -210,7 +209,7 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
|||
//long b = System.currentTimeMillis();
|
||||
for (Block m : mining) {
|
||||
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(m)) {
|
||||
locs.addAll(ctx.worldData().getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), 1, ctx.getBaritone().getPlayerContext().playerFeet().getX(), ctx.getBaritone().getPlayerContext().playerFeet().getZ(), 1));
|
||||
locs.addAll(ctx.worldData.getCachedWorld().getLocationsOf(ChunkPacker.blockToString(m), 1, ctx.getBaritone().getPlayerContext().playerFeet().getX(), ctx.getBaritone().getPlayerContext().playerFeet().getZ(), 2));
|
||||
} else {
|
||||
uninteresting.add(m);
|
||||
}
|
||||
|
@ -249,16 +248,17 @@ public final class MineProcess extends BaritoneProcessHelper implements IMinePro
|
|||
}
|
||||
|
||||
public static List<BlockPos> prune(CalculationContext ctx, List<BlockPos> locs2, List<Block> mining, int max) {
|
||||
List<BlockPos> dropped = droppedItemsScan(mining, ctx.world());
|
||||
List<BlockPos> dropped = droppedItemsScan(mining, ctx.world);
|
||||
List<BlockPos> locs = locs2
|
||||
.stream()
|
||||
.distinct()
|
||||
|
||||
// remove any that are within loaded chunks that aren't actually what we want
|
||||
.filter(pos -> ctx.world().getChunk(pos) instanceof EmptyChunk || mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos))
|
||||
|
||||
.filter(pos -> !ctx.bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ()) || mining.contains(ctx.getBlock(pos.getX(), pos.getY(), pos.getZ())) || dropped.contains(pos))
|
||||
|
||||
// remove any that are implausible to mine (encased in bedrock, or touching lava)
|
||||
.filter(pos -> MineProcess.plausibleToBreak(ctx.bsi(), pos))
|
||||
.filter(pos -> MineProcess.plausibleToBreak(ctx.bsi, pos))
|
||||
|
||||
.sorted(Comparator.comparingDouble(ctx.getBaritone().getPlayerContext().playerFeet()::distanceSq))
|
||||
.collect(Collectors.toList());
|
||||
|
|
|
@ -32,6 +32,15 @@ import net.minecraft.world.GameType;
|
|||
import net.minecraft.world.WorldSettings;
|
||||
import net.minecraft.world.WorldType;
|
||||
|
||||
/**
|
||||
* Responsible for automatically testing Baritone's pathing algorithm by automatically creating a world with a specific
|
||||
* seed, setting a specified goal, and only allowing a certain amount of ticks to pass before the pathing test is
|
||||
* considered a failure. In order to test locally, docker may be used, or through an IDE: Create a run config which runs
|
||||
* in a separate directory from the primary one (./run), and set the enrivonmental variable {@code BARITONE_AUTO_TEST}
|
||||
* to {@code true}.
|
||||
*
|
||||
* @author leijurv, Brady
|
||||
*/
|
||||
public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
|
||||
|
||||
public static final BaritoneAutoTest INSTANCE = new BaritoneAutoTest();
|
||||
|
@ -39,8 +48,8 @@ public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
|
|||
public static final boolean ENABLE_AUTO_TEST = "true".equals(System.getenv("BARITONE_AUTO_TEST"));
|
||||
private static final long TEST_SEED = -928872506371745L;
|
||||
private static final BlockPos STARTING_POSITION = new BlockPos(0, 65, 0);
|
||||
private static final Goal GOAL = new GoalBlock(69, 121, 420);
|
||||
private static final int MAX_TICKS = 3500;
|
||||
private static final Goal GOAL = new GoalBlock(69, 69, 420);
|
||||
private static final int MAX_TICKS = 3300;
|
||||
|
||||
/**
|
||||
* Called right after the {@link GameSettings} object is created in the {@link Minecraft} instance.
|
||||
|
|
|
@ -23,16 +23,10 @@ import baritone.api.utils.IPlayerContext;
|
|||
|
||||
public abstract class BaritoneProcessHelper implements IBaritoneProcess, Helper {
|
||||
|
||||
public static final double DEFAULT_PRIORITY = 0;
|
||||
|
||||
protected final Baritone baritone;
|
||||
protected final IPlayerContext ctx;
|
||||
private final double priority;
|
||||
|
||||
public BaritoneProcessHelper(Baritone baritone) {
|
||||
this(baritone, DEFAULT_PRIORITY);
|
||||
}
|
||||
|
||||
public BaritoneProcessHelper(Baritone baritone, double priority) {
|
||||
this.baritone = baritone;
|
||||
this.ctx = baritone.getPlayerContext();
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
|
||||
package baritone.utils;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.EnumHand;
|
||||
|
@ -31,11 +29,6 @@ import net.minecraft.util.math.RayTraceResult;
|
|||
*/
|
||||
public final class BlockBreakHelper implements Helper {
|
||||
|
||||
/**
|
||||
* The last block that we tried to break, if this value changes
|
||||
* between attempts, then we re-initialize the breaking process.
|
||||
*/
|
||||
private BlockPos lastBlock;
|
||||
private boolean didBreakLastTick;
|
||||
|
||||
private IPlayerContext playerContext;
|
||||
|
@ -45,42 +38,20 @@ public final class BlockBreakHelper implements Helper {
|
|||
}
|
||||
|
||||
public void tryBreakBlock(BlockPos pos, EnumFacing side) {
|
||||
if (!pos.equals(lastBlock)) {
|
||||
playerContext.playerController().clickBlock(pos, side);
|
||||
}
|
||||
if (playerContext.playerController().onPlayerDamageBlock(pos, side)) {
|
||||
playerContext.player().swingArm(EnumHand.MAIN_HAND);
|
||||
}
|
||||
lastBlock = pos;
|
||||
}
|
||||
|
||||
public void stopBreakingBlock() {
|
||||
if (playerContext.playerController() != null) {
|
||||
// The player controller will never be null, but the player can be
|
||||
if (playerContext.player() != null) {
|
||||
playerContext.playerController().resetBlockRemoving();
|
||||
}
|
||||
lastBlock = null;
|
||||
}
|
||||
|
||||
private boolean fakeBreak() {
|
||||
if (playerContext != BaritoneAPI.getProvider().getPrimaryBaritone().getPlayerContext()) {
|
||||
// for a non primary player, we need to fake break always, CLICK_LEFT has no effect
|
||||
return true;
|
||||
}
|
||||
if (!Baritone.settings().leftClickWorkaround.get()) {
|
||||
// if this setting is false, we CLICK_LEFT regardless of gui status
|
||||
return false;
|
||||
}
|
||||
return mc.currentScreen != null;
|
||||
}
|
||||
|
||||
public boolean tick(boolean isLeftClick) {
|
||||
if (!fakeBreak()) {
|
||||
if (didBreakLastTick) {
|
||||
stopBreakingBlock();
|
||||
}
|
||||
return isLeftClick;
|
||||
}
|
||||
|
||||
public void tick(boolean isLeftClick) {
|
||||
RayTraceResult trace = playerContext.objectMouseOver();
|
||||
boolean isBlockTrace = trace != null && trace.typeOfHit == RayTraceResult.Type.BLOCK;
|
||||
|
||||
|
@ -91,6 +62,5 @@ public final class BlockBreakHelper implements Helper {
|
|||
stopBreakingBlock();
|
||||
didBreakLastTick = false;
|
||||
}
|
||||
return false; // fakeBreak is true so no matter what we aren't forcing CLICK_LEFT
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import baritone.cache.CachedRegion;
|
|||
import baritone.cache.WorldData;
|
||||
import baritone.utils.accessor.IChunkProviderClient;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.state.IBlockState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
@ -46,15 +47,27 @@ public class BlockStateInterface {
|
|||
private Chunk prev = null;
|
||||
private CachedRegion prevCached = null;
|
||||
|
||||
private final boolean useTheRealWorld;
|
||||
|
||||
private static final IBlockState AIR = Blocks.AIR.getDefaultState();
|
||||
|
||||
public BlockStateInterface(IPlayerContext ctx) {
|
||||
this(ctx.world(), (WorldData) ctx.worldData());
|
||||
this(ctx, false);
|
||||
}
|
||||
|
||||
public BlockStateInterface(World world, WorldData worldData) {
|
||||
public BlockStateInterface(IPlayerContext ctx, boolean copyLoadedChunks) {
|
||||
this(ctx.world(), (WorldData) ctx.worldData(), copyLoadedChunks);
|
||||
}
|
||||
|
||||
public BlockStateInterface(World world, WorldData worldData, boolean copyLoadedChunks) {
|
||||
this.worldData = worldData;
|
||||
this.loadedChunks = ((IChunkProviderClient) world.getChunkProvider()).loadedChunks();
|
||||
Long2ObjectMap<Chunk> worldLoaded = ((IChunkProviderClient) world.getChunkProvider()).loadedChunks();
|
||||
if (copyLoadedChunks) {
|
||||
this.loadedChunks = new Long2ObjectOpenHashMap<>(worldLoaded); // make a copy that we can safely access from another thread
|
||||
} else {
|
||||
this.loadedChunks = worldLoaded; // this will only be used on the main thread
|
||||
}
|
||||
this.useTheRealWorld = !Baritone.settings().pathThroughCachedOnly.get();
|
||||
if (!Minecraft.getMinecraft().isCallingFromMinecraftThread()) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
@ -85,7 +98,7 @@ public class BlockStateInterface {
|
|||
return AIR;
|
||||
}
|
||||
|
||||
if (!Baritone.settings().pathThroughCachedOnly.get()) {
|
||||
if (useTheRealWorld) {
|
||||
Chunk cached = prev;
|
||||
// there's great cache locality in block state lookups
|
||||
// generally it's within each movement
|
||||
|
|
|
@ -19,6 +19,7 @@ package baritone.utils;
|
|||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.cache.IRememberedInventory;
|
||||
import baritone.api.cache.IWaypoint;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.pathing.goals.*;
|
||||
|
@ -32,10 +33,12 @@ import baritone.pathing.movement.CalculationContext;
|
|||
import baritone.pathing.movement.Movement;
|
||||
import baritone.pathing.movement.Moves;
|
||||
import baritone.process.CustomGoalProcess;
|
||||
import baritone.utils.pathing.SegmentedCalculator;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.client.multiplayer.ChunkProviderClient;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.chunk.Chunk;
|
||||
|
||||
|
@ -202,6 +205,23 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("fullpath")) {
|
||||
if (pathingBehavior.getGoal() == null) {
|
||||
logDirect("No goal.");
|
||||
} else {
|
||||
logDirect("Started segmented calculator");
|
||||
SegmentedCalculator.calculateSegmentsThreaded(pathingBehavior.pathStart(), pathingBehavior.getGoal(), new CalculationContext(baritone, true), ipath -> {
|
||||
logDirect("Found a path");
|
||||
logDirect("Ends at " + ipath.getDest());
|
||||
logDirect("Length " + ipath.length());
|
||||
logDirect("Estimated time " + ipath.ticksRemainingFrom(0));
|
||||
pathingBehavior.secretCursedFunctionDoNotCall(ipath); // it's okay when *I* do it
|
||||
}, () -> {
|
||||
logDirect("Path calculation failed, no path");
|
||||
});
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("repack") || msg.equals("rescan")) {
|
||||
ChunkProviderClient cli = (ChunkProviderClient) ctx.world().getChunkProvider();
|
||||
int playerChunkX = ctx.playerFeet().getX() >> 4;
|
||||
|
@ -259,6 +279,38 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
|||
});
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("reset")) {
|
||||
Baritone.settings().reset();
|
||||
logDirect("Baritone settings reset");
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("echest")) {
|
||||
Optional<List<ItemStack>> contents = baritone.getMemoryBehavior().echest();
|
||||
if (contents.isPresent()) {
|
||||
logDirect("echest contents:");
|
||||
log(contents.get());
|
||||
} else {
|
||||
logDirect("echest contents unknown");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (msg.equals("chests")) {
|
||||
System.out.println(baritone.getWorldProvider());
|
||||
System.out.println(baritone.getWorldProvider().getCurrentWorld());
|
||||
|
||||
System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory());
|
||||
|
||||
System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories());
|
||||
|
||||
System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet());
|
||||
|
||||
System.out.println(baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet());
|
||||
for (Map.Entry<BlockPos, IRememberedInventory> entry : baritone.getWorldProvider().getCurrentWorld().getContainerMemory().getRememberedInventories().entrySet()) {
|
||||
logDirect(entry.getKey() + "");
|
||||
log(entry.getValue().getContents());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (msg.startsWith("followplayers")) {
|
||||
baritone.getFollowProcess().follow(EntityPlayer.class::isInstance); // O P P A
|
||||
logDirect("Following any players");
|
||||
|
@ -468,4 +520,12 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void log(List<ItemStack> stacks) {
|
||||
for (ItemStack stack : stacks) {
|
||||
if (!stack.isEmpty()) {
|
||||
logDirect(stack.getCount() + "x " + stack.getDisplayName() + "@" + stack.getItemDamage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public interface Helper {
|
|||
/**
|
||||
* Send a message to chat only if chatDebug is on
|
||||
*
|
||||
* @param message
|
||||
* @param message The message to display in chat
|
||||
*/
|
||||
default void logDebug(String message) {
|
||||
if (!Baritone.settings().chatDebug.get()) {
|
||||
|
@ -61,12 +61,12 @@ public interface Helper {
|
|||
/**
|
||||
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a direct response to a chat command)
|
||||
*
|
||||
* @param message
|
||||
* @param message The message to display in chat
|
||||
*/
|
||||
default void logDirect(String message) {
|
||||
ITextComponent component = MESSAGE_PREFIX.createCopy();
|
||||
component.getStyle().setColor(TextFormatting.GRAY);
|
||||
component.appendSibling(new TextComponentString(" " + message));
|
||||
Baritone.settings().logger.get().accept(component);
|
||||
Minecraft.getMinecraft().addScheduledTask(() -> Baritone.settings().logger.get().accept(component));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,12 +18,15 @@
|
|||
package baritone.utils;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.utils.IInputOverrideHandler;
|
||||
import baritone.api.utils.input.Input;
|
||||
import baritone.behavior.Behavior;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.settings.KeyBinding;
|
||||
import org.lwjgl.input.Keyboard;
|
||||
import net.minecraft.util.MovementInput;
|
||||
import net.minecraft.util.MovementInputFromOptions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
@ -57,8 +60,18 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri
|
|||
* @return Whether or not it is being forced down
|
||||
*/
|
||||
@Override
|
||||
public final boolean isInputForcedDown(KeyBinding key) {
|
||||
return isInputForcedDown(Input.getInputForBind(key));
|
||||
public final Boolean isInputForcedDown(KeyBinding key) {
|
||||
Input input = Input.getInputForBind(key);
|
||||
if (input == null || !inControl()) {
|
||||
return null;
|
||||
}
|
||||
if (input == Input.CLICK_LEFT) {
|
||||
return false;
|
||||
}
|
||||
if (input == Input.CLICK_RIGHT) {
|
||||
return isInputForcedDown(Input.CLICK_RIGHT);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -91,29 +104,25 @@ public final class InputOverrideHandler extends Behavior implements IInputOverri
|
|||
this.inputForceStateMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onProcessKeyBinds() {
|
||||
// Simulate the key being held down this tick
|
||||
for (Input input : Input.values()) {
|
||||
KeyBinding keyBinding = input.getKeyBinding();
|
||||
|
||||
if (isInputForcedDown(keyBinding) && !keyBinding.isKeyDown()) {
|
||||
int keyCode = keyBinding.getKeyCode();
|
||||
|
||||
if (keyCode < Keyboard.KEYBOARD_SIZE) {
|
||||
KeyBinding.onTick(keyCode < 0 ? keyCode + 100 : keyCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onTick(TickEvent event) {
|
||||
if (event.getType() == TickEvent.Type.OUT) {
|
||||
return;
|
||||
}
|
||||
boolean stillClick = blockBreakHelper.tick(isInputForcedDown(Input.CLICK_LEFT));
|
||||
setInputForceState(Input.CLICK_LEFT, stillClick);
|
||||
blockBreakHelper.tick(isInputForcedDown(Input.CLICK_LEFT));
|
||||
|
||||
MovementInput desired = inControl()
|
||||
? new PlayerMovementInput(this)
|
||||
: new MovementInputFromOptions(Minecraft.getMinecraft().gameSettings);
|
||||
|
||||
if (ctx.player().movementInput.getClass() != desired.getClass()) {
|
||||
ctx.player().movementInput = desired; // only set it if it was previously incorrect
|
||||
// gotta do it this way, or else it constantly thinks you're beginning a double tap W sprint lol
|
||||
}
|
||||
}
|
||||
|
||||
private boolean inControl() {
|
||||
return baritone.getPathingBehavior().isPathing() || baritone != BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||
}
|
||||
|
||||
public BlockBreakHelper getBlockBreakHelper() {
|
||||
|
|
|
@ -21,10 +21,7 @@ import baritone.Baritone;
|
|||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.event.events.RenderEvent;
|
||||
import baritone.api.pathing.calc.IPath;
|
||||
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.pathing.goals.*;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
|
@ -33,6 +30,7 @@ import net.minecraft.block.state.IBlockState;
|
|||
import net.minecraft.client.renderer.BufferBuilder;
|
||||
import net.minecraft.client.renderer.GlStateManager;
|
||||
import net.minecraft.client.renderer.Tessellator;
|
||||
import net.minecraft.client.renderer.tileentity.TileEntityBeaconRenderer;
|
||||
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.init.Blocks;
|
||||
|
@ -282,14 +280,14 @@ public final class PathRenderer implements Helper {
|
|||
minZ = goalPos.getZ() + 0.002 - renderPosZ;
|
||||
maxZ = goalPos.getZ() + 1 - 0.002 - renderPosZ;
|
||||
double y = MathHelper.cos((float) (((float) ((System.nanoTime() / 100000L) % 20000L)) / 20000F * Math.PI * 2));
|
||||
if (goal instanceof GoalTwoBlocks) {
|
||||
if (goal instanceof GoalGetToBlock || goal instanceof GoalTwoBlocks) {
|
||||
y /= 2;
|
||||
}
|
||||
y1 = 1 + y + goalPos.getY() - renderPosY;
|
||||
y2 = 1 - y + goalPos.getY() - renderPosY;
|
||||
minY = goalPos.getY() - renderPosY;
|
||||
maxY = minY + 2;
|
||||
if (goal instanceof GoalTwoBlocks) {
|
||||
if (goal instanceof GoalGetToBlock || goal instanceof GoalTwoBlocks) {
|
||||
y1 -= 0.5;
|
||||
y2 -= 0.5;
|
||||
maxY--;
|
||||
|
@ -297,6 +295,31 @@ public final class PathRenderer implements Helper {
|
|||
} else if (goal instanceof GoalXZ) {
|
||||
GoalXZ goalPos = (GoalXZ) goal;
|
||||
|
||||
if (Baritone.settings().renderGoalXZBeacon.get()) {
|
||||
mc.getTextureManager().bindTexture(TileEntityBeaconRenderer.TEXTURE_BEACON_BEAM);
|
||||
|
||||
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
|
||||
GlStateManager.disableDepth();
|
||||
}
|
||||
|
||||
TileEntityBeaconRenderer.renderBeamSegment(
|
||||
goalPos.getX() - renderPosX,
|
||||
-renderPosY,
|
||||
goalPos.getZ() - renderPosZ,
|
||||
partialTicks,
|
||||
1.0,
|
||||
player.world.getTotalWorldTime(),
|
||||
0,
|
||||
256,
|
||||
color.getColorComponents(null)
|
||||
);
|
||||
|
||||
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
|
||||
GlStateManager.enableDepth();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
minX = goalPos.getX() + 0.002 - renderPosX;
|
||||
maxX = goalPos.getX() + 1 - 0.002 - renderPosX;
|
||||
minZ = goalPos.getZ() + 0.002 - renderPosZ;
|
||||
|
|
|
@ -29,7 +29,7 @@ import baritone.pathing.path.PathExecutor;
|
|||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class PathingControlManager implements IPathingControlManager {
|
||||
private final Baritone baritone;
|
||||
|
@ -64,8 +64,7 @@ public class PathingControlManager implements IPathingControlManager {
|
|||
command = null;
|
||||
for (IBaritoneProcess proc : processes) {
|
||||
proc.onLostControl();
|
||||
if (proc.isActive() && !proc.isTemporary()) { // it's okay for a temporary thing (like combat pause) to maintain control even if you say to cancel
|
||||
// but not for a non temporary thing
|
||||
if (proc.isActive() && !proc.isTemporary()) { // it's okay only for a temporary thing (like combat pause) to maintain control even if you say to cancel
|
||||
throw new IllegalStateException(proc.displayName());
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +82,12 @@ public class PathingControlManager implements IPathingControlManager {
|
|||
|
||||
public void preTick() {
|
||||
inControlLastTick = inControlThisTick;
|
||||
command = doTheStuff();
|
||||
PathingBehavior p = baritone.getPathingBehavior();
|
||||
command = executeProcesses();
|
||||
if (command == null) {
|
||||
p.cancelSegmentIfSafe();
|
||||
return;
|
||||
}
|
||||
PathingBehavior p = baritone.getPathingBehavior();
|
||||
switch (command.commandType) {
|
||||
case REQUEST_PAUSE:
|
||||
p.requestPause();
|
||||
|
@ -170,32 +170,30 @@ public class PathingControlManager implements IPathingControlManager {
|
|||
}
|
||||
|
||||
|
||||
public PathingCommand doTheStuff() {
|
||||
List<IBaritoneProcess> inContention = processes.stream().filter(IBaritoneProcess::isActive).sorted(Comparator.comparingDouble(IBaritoneProcess::priority)).collect(Collectors.toList());
|
||||
boolean found = false;
|
||||
boolean cancelOthers = false;
|
||||
PathingCommand exec = null;
|
||||
for (int i = inContention.size() - 1; i >= 0; i--) { // truly a gamer moment
|
||||
IBaritoneProcess proc = inContention.get(i);
|
||||
if (found) {
|
||||
if (cancelOthers) {
|
||||
proc.onLostControl();
|
||||
}
|
||||
} else {
|
||||
exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel());
|
||||
public PathingCommand executeProcesses() {
|
||||
Stream<IBaritoneProcess> inContention = processes.stream()
|
||||
.filter(IBaritoneProcess::isActive)
|
||||
.sorted(Comparator.comparingDouble(IBaritoneProcess::priority).reversed());
|
||||
|
||||
|
||||
Iterator<IBaritoneProcess> iterator = inContention.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
IBaritoneProcess proc = iterator.next();
|
||||
|
||||
PathingCommand exec = proc.onTick(Objects.equals(proc, inControlLastTick) && baritone.getPathingBehavior().calcFailedLastTick(), baritone.getPathingBehavior().isSafeToCancel());
|
||||
if (exec == null) {
|
||||
if (proc.isActive()) {
|
||||
throw new IllegalStateException(proc.displayName());
|
||||
throw new IllegalStateException(proc.displayName() + " returned null PathingCommand");
|
||||
}
|
||||
proc.onLostControl();
|
||||
continue;
|
||||
}
|
||||
//System.out.println("Executing command " + exec.commandType + " " + exec.goal + " from " + proc.displayName());
|
||||
} else {
|
||||
inControlThisTick = proc;
|
||||
found = true;
|
||||
cancelOthers = !proc.isTemporary();
|
||||
}
|
||||
if (!proc.isTemporary()) {
|
||||
iterator.forEachRemaining(IBaritoneProcess::onLostControl);
|
||||
}
|
||||
return exec;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils;
|
||||
|
||||
import baritone.api.utils.input.Input;
|
||||
import net.minecraft.util.MovementInput;
|
||||
|
||||
public class PlayerMovementInput extends MovementInput {
|
||||
private final InputOverrideHandler handler;
|
||||
|
||||
public PlayerMovementInput(InputOverrideHandler handler) {
|
||||
this.handler = handler;
|
||||
}
|
||||
|
||||
public void updatePlayerMoveState() {
|
||||
this.moveStrafe = 0.0F;
|
||||
this.moveForward = 0.0F;
|
||||
|
||||
jump = handler.isInputForcedDown(Input.JUMP); // oppa
|
||||
|
||||
if (this.forwardKeyDown = handler.isInputForcedDown(Input.MOVE_FORWARD)) {
|
||||
this.moveForward++;
|
||||
}
|
||||
|
||||
if (this.backKeyDown = handler.isInputForcedDown(Input.MOVE_BACK)) {
|
||||
this.moveForward--;
|
||||
}
|
||||
|
||||
if (this.leftKeyDown = handler.isInputForcedDown(Input.MOVE_LEFT)) {
|
||||
this.moveStrafe++;
|
||||
}
|
||||
|
||||
if (this.rightKeyDown = handler.isInputForcedDown(Input.MOVE_RIGHT)) {
|
||||
this.moveStrafe--;
|
||||
}
|
||||
|
||||
if (this.sneak = handler.isInputForcedDown(Input.SNEAK)) {
|
||||
this.moveStrafe *= 0.3D;
|
||||
this.moveForward *= 0.3D;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -103,7 +103,7 @@ public class ToolSet {
|
|||
IBlockState blockState = b.getDefaultState();
|
||||
for (byte i = 0; i < 9; i++) {
|
||||
ItemStack itemStack = player.inventory.getStackInSlot(i);
|
||||
double v = calculateStrVsBlock(itemStack, blockState);
|
||||
double v = calculateSpeedVsBlock(itemStack, blockState);
|
||||
if (v > value) {
|
||||
value = v;
|
||||
best = i;
|
||||
|
@ -128,7 +128,7 @@ public class ToolSet {
|
|||
*/
|
||||
private double getBestDestructionTime(Block b) {
|
||||
ItemStack stack = player.inventory.getStackInSlot(getBestSlot(b));
|
||||
return calculateStrVsBlock(stack, b.getDefaultState());
|
||||
return calculateSpeedVsBlock(stack, b.getDefaultState());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -138,7 +138,7 @@ public class ToolSet {
|
|||
* @param state the blockstate to be mined
|
||||
* @return how long it would take in ticks
|
||||
*/
|
||||
private double calculateStrVsBlock(ItemStack item, IBlockState state) {
|
||||
public static double calculateSpeedVsBlock(ItemStack item, IBlockState state) {
|
||||
float hardness = state.getBlockHardness(null, null);
|
||||
if (hardness < 0) {
|
||||
return -1;
|
||||
|
@ -154,11 +154,10 @@ public class ToolSet {
|
|||
|
||||
speed /= hardness;
|
||||
if (state.getMaterial().isToolNotRequired() || (!item.isEmpty() && item.canHarvestBlock(state))) {
|
||||
speed /= 30;
|
||||
return speed / 30;
|
||||
} else {
|
||||
speed /= 100;
|
||||
return speed / 100;
|
||||
}
|
||||
return speed;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -180,7 +179,7 @@ public class ToolSet {
|
|||
speed *= 0.09;
|
||||
break;
|
||||
case 2:
|
||||
speed *= 0.0027;
|
||||
speed *= 0.0027; // you might think that 0.09*0.3 = 0.027 so that should be next, that would make too much sense. it's 0.0027.
|
||||
break;
|
||||
default:
|
||||
speed *= 0.00081;
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils.pathing;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap;
|
||||
import net.minecraft.entity.monster.EntityMob;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Avoidance {
|
||||
private final int centerX;
|
||||
private final int centerY;
|
||||
private final int centerZ;
|
||||
private final double coefficient;
|
||||
private final int radius;
|
||||
private final int radiusSq;
|
||||
|
||||
public Avoidance(BlockPos center, double coefficient, int radius) {
|
||||
this(center.getX(), center.getY(), center.getZ(), coefficient, radius);
|
||||
}
|
||||
|
||||
public Avoidance(int centerX, int centerY, int centerZ, double coefficient, int radius) {
|
||||
this.centerX = centerX;
|
||||
this.centerY = centerY;
|
||||
this.centerZ = centerZ;
|
||||
this.coefficient = coefficient;
|
||||
this.radius = radius;
|
||||
this.radiusSq = radius * radius;
|
||||
}
|
||||
|
||||
public double coefficient(int x, int y, int z) {
|
||||
int xDiff = x - centerX;
|
||||
int yDiff = y - centerY;
|
||||
int zDiff = z - centerZ;
|
||||
return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff <= radiusSq ? coefficient : 1.0D;
|
||||
}
|
||||
|
||||
public static List<Avoidance> create(IPlayerContext ctx) {
|
||||
if (!Baritone.settings().avoidance.get()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<Avoidance> res = new ArrayList<>();
|
||||
double mobSpawnerCoeff = Baritone.settings().mobSpawnerAvoidanceCoefficient.get();
|
||||
double mobCoeff = Baritone.settings().mobAvoidanceCoefficient.get();
|
||||
if (mobSpawnerCoeff != 1.0D) {
|
||||
ctx.worldData().getCachedWorld().getLocationsOf("mob_spawner", 1, ctx.playerFeet().x, ctx.playerFeet().z, 2).forEach(mobspawner -> res.add(new Avoidance(mobspawner, mobSpawnerCoeff, Baritone.settings().mobSpawnerAvoidanceRadius.get())));
|
||||
}
|
||||
if (mobCoeff != 1.0D) {
|
||||
ctx.world().loadedEntityList.stream().filter(entity -> entity instanceof EntityMob).forEach(entity -> res.add(new Avoidance(new BlockPos(entity), mobCoeff, Baritone.settings().mobAvoidanceRadius.get())));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
public void applySpherical(Long2DoubleOpenHashMap map) {
|
||||
for (int x = -radius; x <= radius; x++) {
|
||||
for (int y = -radius; y <= radius; y++) {
|
||||
for (int z = -radius; z <= radius; z++) {
|
||||
if (x * x + y * y + z * z <= radius * radius) {
|
||||
long hash = BetterBlockPos.longHash(centerX + x, centerY + y, centerZ + z);
|
||||
map.put(hash, map.get(hash) * coefficient);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils.pathing;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.pathing.calc.IPath;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import it.unimi.dsi.fastutil.longs.Long2DoubleOpenHashMap;
|
||||
|
||||
public final class Favoring {
|
||||
private final Long2DoubleOpenHashMap favorings;
|
||||
|
||||
public Favoring(IPlayerContext ctx, IPath previous) {
|
||||
this(previous);
|
||||
for (Avoidance avoid : Avoidance.create(ctx)) {
|
||||
avoid.applySpherical(favorings);
|
||||
}
|
||||
System.out.println("Favoring size: " + favorings.size());
|
||||
}
|
||||
|
||||
public Favoring(IPath previous) { // create one just from previous path, no mob avoidances
|
||||
favorings = new Long2DoubleOpenHashMap();
|
||||
favorings.defaultReturnValue(1.0D);
|
||||
double coeff = Baritone.settings().backtrackCostFavoringCoefficient.get();
|
||||
if (coeff != 1D && previous != null) {
|
||||
previous.positions().forEach(pos -> favorings.put(BetterBlockPos.longHash(pos), coeff));
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return favorings.isEmpty();
|
||||
}
|
||||
|
||||
public double calculate(long hash) {
|
||||
return favorings.get(hash);
|
||||
}
|
||||
}
|
|
@ -21,16 +21,16 @@ import baritone.api.BaritoneAPI;
|
|||
import baritone.api.pathing.calc.IPath;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.pathing.path.CutoffPath;
|
||||
import baritone.utils.BlockStateInterface;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.World;
|
||||
import net.minecraft.world.chunk.EmptyChunk;
|
||||
|
||||
public abstract class PathBase implements IPath {
|
||||
@Override
|
||||
public IPath cutoffAtLoadedChunks(World world) {
|
||||
public PathBase cutoffAtLoadedChunks(Object bsi0) { // <-- cursed cursed cursed
|
||||
BlockStateInterface bsi = (BlockStateInterface) bsi0;
|
||||
for (int i = 0; i < positions().size(); i++) {
|
||||
BlockPos pos = positions().get(i);
|
||||
if (world.getChunk(pos) instanceof EmptyChunk) {
|
||||
if (!bsi.worldContainsLoadedChunk(pos.getX(), pos.getZ())) {
|
||||
return new CutoffPath(this, i);
|
||||
}
|
||||
}
|
||||
|
@ -38,15 +38,16 @@ public abstract class PathBase implements IPath {
|
|||
}
|
||||
|
||||
@Override
|
||||
public IPath staticCutoff(Goal destination) {
|
||||
if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) {
|
||||
public PathBase staticCutoff(Goal destination) {
|
||||
int min = BaritoneAPI.getSettings().pathCutoffMinimumLength.get();
|
||||
if (length() < min) {
|
||||
return this;
|
||||
}
|
||||
if (destination == null || destination.isInGoal(getDest())) {
|
||||
return this;
|
||||
}
|
||||
double factor = BaritoneAPI.getSettings().pathCutoffFactor.get();
|
||||
int newLength = (int) ((length() - 1) * factor);
|
||||
int newLength = (int) ((length() - min) * factor) + min - 1;
|
||||
return new CutoffPath(this, newLength);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,10 +22,12 @@ import baritone.api.pathing.calc.IPath;
|
|||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.PathCalculationResult;
|
||||
import baritone.behavior.PathingBehavior;
|
||||
import baritone.cache.CachedWorld;
|
||||
import baritone.pathing.calc.AStarPathFinder;
|
||||
import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.path.SplicedPath;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -52,8 +54,8 @@ public class SegmentedCalculator {
|
|||
PathCalculationResult result = segment(soFar);
|
||||
switch (result.getType()) {
|
||||
case SUCCESS_SEGMENT:
|
||||
case SUCCESS_TO_GOAL:
|
||||
break;
|
||||
case SUCCESS_TO_GOAL: // if we've gotten all the way to the goal, we're done
|
||||
case FAILURE: // if path calculation failed, we're done
|
||||
case EXCEPTION: // if path calculation threw an exception, we're done
|
||||
return soFar;
|
||||
|
@ -62,13 +64,30 @@ public class SegmentedCalculator {
|
|||
}
|
||||
IPath segment = result.getPath().get(); // path calculation result type is SUCCESS_SEGMENT, so the path must be present
|
||||
IPath combined = soFar.map(previous -> (IPath) SplicedPath.trySplice(previous, segment, true).get()).orElse(segment);
|
||||
loadAdjacent(combined.getDest().getX(), combined.getDest().getZ());
|
||||
soFar = Optional.of(combined);
|
||||
if (result.getType() == PathCalculationResult.Type.SUCCESS_TO_GOAL) {
|
||||
return soFar;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void loadAdjacent(int blockX, int blockZ) {
|
||||
BetterBlockPos bp = new BetterBlockPos(blockX, 64, blockZ);
|
||||
CachedWorld cached = (CachedWorld) context.getBaritone().getPlayerContext().worldData().getCachedWorld();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
// pathing thread is not allowed to load new cached regions from disk
|
||||
// it checks if every chunk is loaded before getting blocks from it
|
||||
// so you see path segments ending at multiples of 512 (plus or minus one) on either x or z axis
|
||||
// this loads every adjacent chunk to the segment end, so it can continue into the next cached region
|
||||
BetterBlockPos toLoad = bp.offset(EnumFacing.byHorizontalIndex(i), 16);
|
||||
cached.tryLoadFromDisk(toLoad.x >> 9, toLoad.z >> 9);
|
||||
}
|
||||
}
|
||||
|
||||
private PathCalculationResult segment(Optional<IPath> previous) {
|
||||
BetterBlockPos segmentStart = previous.map(IPath::getDest).orElse(start); // <-- e p i c
|
||||
AbstractNodeCostSearch search = PathingBehavior.createPathfinder(segmentStart, goal, previous.orElse(null), context);
|
||||
AbstractNodeCostSearch search = new AStarPathFinder(segmentStart.x, segmentStart.y, segmentStart.z, goal, new Favoring(previous.orElse(null)), context); // this is on another thread, so cannot include mob avoidances.
|
||||
return search.calculate(Baritone.settings().primaryTimeoutMS.get(), Baritone.settings().failureTimeoutMS.get()); // use normal time settings, not the plan ahead settings, so as to not overwhelm the computer
|
||||
}
|
||||
|
||||
|
|
|
@ -20,9 +20,9 @@ package baritone.utils.player;
|
|||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.cache.IWorldData;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.IPlayerController;
|
||||
import baritone.utils.Helper;
|
||||
import net.minecraft.client.entity.EntityPlayerSP;
|
||||
import net.minecraft.client.multiplayer.PlayerControllerMP;
|
||||
import net.minecraft.util.math.RayTraceResult;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
|
@ -42,8 +42,8 @@ public enum PrimaryPlayerContext implements IPlayerContext, Helper {
|
|||
}
|
||||
|
||||
@Override
|
||||
public PlayerControllerMP playerController() {
|
||||
return mc.playerController;
|
||||
public IPlayerController playerController() {
|
||||
return PrimaryPlayerController.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* Baritone is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package baritone.utils.player;
|
||||
|
||||
import baritone.api.utils.IPlayerController;
|
||||
import baritone.utils.Helper;
|
||||
import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.inventory.ClickType;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.util.EnumFacing;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.world.GameType;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 12/14/2018
|
||||
*/
|
||||
public enum PrimaryPlayerController implements IPlayerController, Helper {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public boolean onPlayerDamageBlock(BlockPos pos, EnumFacing side) {
|
||||
return mc.playerController.onPlayerDamageBlock(pos, side);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetBlockRemoving() {
|
||||
mc.playerController.resetBlockRemoving();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ItemStack windowClick(int windowId, int slotId, int mouseButton, ClickType type, EntityPlayer player) {
|
||||
return mc.playerController.windowClick(windowId, slotId, mouseButton, type, player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGameType(GameType type) {
|
||||
mc.playerController.setGameType(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public GameType getGameType() {
|
||||
return mc.playerController.getCurrentGameType();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue