mirror of
https://github.com/cabaletta/baritone
synced 2025-02-19 13:37:03 +00:00
Merge branch '1.19.4' into 1.20.1
This commit is contained in:
commit
51843f7074
6
.gitignore
vendored
6
.gitignore
vendored
@ -37,4 +37,8 @@ baritone_Client.launch
|
||||
.vscode/launch.json
|
||||
.architectury-transformer
|
||||
|
||||
mapping
|
||||
|
||||
mapping
|
||||
|
||||
libs/lwjgl-platform-2.9.4-nightly-20150209-natives-osx.jar
|
||||
libs/java-objc-bridge-1.1.jar
|
||||
|
51
README.md
51
README.md
@ -4,13 +4,16 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://github.com/cabaletta/baritone/tree/master"><img src="https://img.shields.io/badge/MC-1.12.2-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.13.2"><img src="https://img.shields.io/badge/MC-1.13.2-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.14.4"><img src="https://img.shields.io/badge/MC-1.14.4-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.15.2"><img src="https://img.shields.io/badge/MC-1.15.2-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.16.5"><img src="https://img.shields.io/badge/MC-1.16.5-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.17.1"><img src="https://img.shields.io/badge/MC-1.17.1-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="https://github.com/cabaletta/baritone/tree/1.18.2"><img src="https://img.shields.io/badge/MC-1.18.2-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.12.2-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.13.2-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.14.4-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.15.2-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.16.5-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.17.1-yellow.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.18.2-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.19.2-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.19.4-brightgreen.svg" alt="Minecraft"/></a>
|
||||
<a href="#Baritone"><img src="https://img.shields.io/badge/MC-1.20.1-brightgreen.svg" alt="Minecraft"/></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
@ -28,12 +31,13 @@
|
||||
<a href="https://github.com/cabaletta/baritone/commit/"><img src="https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg" alt="GitHub commits"/></a>
|
||||
<img src="https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg" alt="Code size"/>
|
||||
<img src="https://img.shields.io/github/repo-size/cabaletta/baritone.svg" alt="GitHub repo size"/>
|
||||
<img src="https://tokei.rs/b1/github/cabaletta/baritone?category=code" alt="Lines of Code"/>
|
||||
<img src="https://tokei.rs/b1/github/cabaletta/baritone?category=code&style=flat" alt="Lines of Code"/>
|
||||
<img src="https://img.shields.io/badge/Badges-36-blue.svg" alt="yes"/>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://impactclient.net/"><img src="https://img.shields.io/badge/Impact%20integration-v1.2.14%20/%20v1.3.8%20/%20v1.4.6%20/%20v1.5.3%20/%20v1.6.3-brightgreen.svg" alt="Impact integration"/></a>
|
||||
<a href="https://github.com/kami-blue/client"><img src="https://img.shields.io/badge/KAMI%20Blue%20integration-v1.2.14--master-green" alt="KAMI Blue integration"/></a>
|
||||
<a href="https://github.com/lambda-client/lambda"><img src="https://img.shields.io/badge/Lambda%20integration-v1.2.17-brightgreen.svg" alt="Lambda integration"/></a>
|
||||
<a href="https://github.com/fr1kin/ForgeHax/"><img src="https://img.shields.io/badge/ForgeHax%20%22integration%22-scuffed-yellow.svg" alt="ForgeHax integration"/></a>
|
||||
<a href="https://aristois.net/"><img src="https://img.shields.io/badge/Aristois%20add--on%20integration-v1.6.3-green.svg" alt="Aristois add-on integration"/></a>
|
||||
<a href="https://rootnet.dev/"><img src="https://img.shields.io/badge/rootNET%20integration-v1.2.14-green.svg" alt="rootNET integration"/></a>
|
||||
@ -42,27 +46,34 @@
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/built-with-swag.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://web.archive.org/web/20230604002050/https://forthebadge.com/images/badges/built-with-swag.svg" alt="forthebadge"/></a>
|
||||
<a href="http://forthebadge.com/"><img src="https://web.archive.org/web/20230604002050/https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg" alt="forthebadge"/></a>
|
||||
</p>
|
||||
|
||||
A Minecraft pathfinder bot.
|
||||
|
||||
Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do.
|
||||
|
||||
[**Baritone Discord Server**](http://discord.gg/s6fRBAUpmr)
|
||||
|
||||
Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#0730 on Baritone which I recommend. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do.
|
||||
**Quick download links:**
|
||||
|
||||
[Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa)
|
||||
| Forge | Fabric |
|
||||
|---------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------|
|
||||
| [1.12.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.2.18/baritone-api-forge-1.2.18.jar) | |
|
||||
| [1.16.5 Forge](https://github.com/cabaletta/baritone/releases/download/v1.6.5/baritone-api-forge-1.6.5.jar) | [1.16.5 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.6.5/baritone-api-fabric-1.6.5.jar) |
|
||||
| [1.17.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-forge-1.7.3.jar) | [1.17.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.7.3/baritone-api-fabric-1.7.3.jar) |
|
||||
| [1.18.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.8.5/baritone-api-forge-1.8.5.jar) | [1.18.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.8.5/baritone-api-fabric-1.8.5.jar) |
|
||||
| [1.19.2 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-forge-1.9.4.jar) | [1.19.2 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.4/baritone-api-fabric-1.9.4.jar) |
|
||||
| [1.19.3 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-forge-1.9.1.jar) | [1.19.3 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.1/baritone-api-fabric-1.9.1.jar) |
|
||||
| [1.19.4 Forge](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-forge-1.9.3.jar) | [1.19.4 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.9.3/baritone-api-fabric-1.9.3.jar) |
|
||||
| [1.20.1 Forge](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-forge-1.10.1.jar) | [1.20.1 Fabric](https://github.com/cabaletta/baritone/releases/download/v1.10.1/baritone-api-fabric-1.10.1.jar) |
|
||||
|
||||
The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to
|
||||
install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click
|
||||
[here](https://github.com/cabaletta/baritone/releases/download/v1.2.17/baritone-api-forge-1.2.17.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it.
|
||||
**Message for 2b2t players looking for 1.19/1.20 Baritone** Download it from right above ^. But also please check back in a few days for Baritone Elytra ([vid 1](https://youtu.be/4bGGPo8yiHo) [vid 2](https://www.youtube.com/watch?v=pUN9nmINe3I)), which will be ported to 1.19/1.20 soon! It will work on 2b2t with its anticheat, that was the whole point of Baritone Elytra (it's fully vanilla compatible). Also join [**the discord**](http://discord.gg/s6fRBAUpmr). Thanks!
|
||||
|
||||
For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge or Fabric 1.16.5, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.3) and get the `api-forge` or `api-fabric` jar. **For 1.16.5 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.6.3/baritone-api-fabric-1.6.3.jar)**.
|
||||
**How to immediately get started:** Type `#goto 1000 500` in chat to go to x=1000 z=500. Type `#mine diamond_ore` to mine diamond ore. Type `#stop` to stop. For more, read [the usage page](USAGE.md) and/or watch this [tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa). Also try `#elytra` for Elytra flying in the Nether using fireworks.
|
||||
|
||||
If you need Forge or Fabric 1.17.1, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.7.2) and get the `api-forge` or `api-fabric` jar. **For 1.17.1 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.7.2/baritone-api-fabric-1.7.2.jar)**.
|
||||
|
||||
If you need Forge or Fabric 1.18.2, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.8.3) and get the `api-forge` or `api-fabric` jar. **For 1.18.2 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.8.3/baritone-api-fabric-1.8.3.jar)**. **For 1.18.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.8.3/baritone-api-forge-1.8.3.jar)**.
|
||||
For other versions of Minecraft or more complicated situations or for development, see [Installation & setup](SETUP.md). Also consider just installing [Impact](https://impactclient.net/), which comes with Baritone and is easier to install than wrangling with version JSONs and zips. For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#6313 on Baritone which I recommend.
|
||||
|
||||
This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/),
|
||||
the original version of the bot for Minecraft 1.8.9, rebuilt for 1.12.2 onwards. Baritone focuses on reliability and particularly performance (it's over [30x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths).
|
||||
|
67
SETUP.md
67
SETUP.md
@ -43,13 +43,13 @@ If another one of your Forge mods has a Baritone integration, you want `baritone
|
||||
## Command Line
|
||||
On Mac OSX and Linux, use `./gradlew` instead of `gradlew`.
|
||||
|
||||
If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16 for 1.17.1, and JDK 17 for 1.18.1.
|
||||
If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8 for 1.12.2-1.16.5, JDK 16+ for 1.17.1, and JDK 17+ for 1.18.1.
|
||||
|
||||
To check which java you are using do
|
||||
`java -version` in a command prompt or terminal.
|
||||
If you are using anything above OpenJDK 8 for 1.12.2-1.16.5, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes.
|
||||
|
||||
Open JDK download: https://openjdk.java.net/install/
|
||||
Download java: https://adoptium.net/
|
||||
#### macOS guide
|
||||
In order to get JDK 8, Try running the following command:
|
||||
`% /usr/libexec/java_home -V`
|
||||
@ -66,68 +66,13 @@ In order to get JDK 8 running in the **current terminal window** you will have t
|
||||
|
||||
To add OpenJDK 8 to your PATH add the export line to the end of your `.zshrc / .bashrc` if you want it to apply to each new terminal. If you're using bash change the .bachrc and if you're using zsh change the .zshrc
|
||||
|
||||
Setting up the Environment:
|
||||
### Building Baritone
|
||||
|
||||
```
|
||||
$ gradlew setupDecompWorkspace
|
||||
$ gradlew --refresh-dependencies
|
||||
```
|
||||
These tasks depend on the minecraft version, but are (for the most part) standard for building mods.
|
||||
|
||||
Building Baritone:
|
||||
|
||||
```
|
||||
$ gradlew build
|
||||
```
|
||||
|
||||
For minecraft 1.15.2+, run the following instead to include the Forge jars:
|
||||
|
||||
```
|
||||
$ gradlew build -Pbaritone.forge_build
|
||||
```
|
||||
|
||||
Do this instead for Fabric jars:
|
||||
|
||||
```
|
||||
$ gradlew build -Pbaritone.fabric_build
|
||||
```
|
||||
|
||||
Running Baritone:
|
||||
|
||||
```
|
||||
$ gradlew runClient
|
||||
```
|
||||
|
||||
For information on how to build baritone, see [Building Baritone](#building-baritone)
|
||||
for more details, see [the build ci action](/.github/workflows/gradle_build.yml)
|
||||
|
||||
## IntelliJ
|
||||
- Open the project in IntelliJ as a Gradle project
|
||||
|
||||

|
||||
|
||||
- Run the Gradle tasks `setupDecompWorkspace` then `genIntellijRuns`
|
||||
|
||||

|
||||
|
||||
- Refresh the Gradle project (or, to be safe, just restart IntelliJ)
|
||||
|
||||

|
||||
|
||||
- Select the "Minecraft Client" launch config
|
||||
|
||||

|
||||
|
||||
- Click on ``Edit Configurations...`` from the same dropdown and select the "Minecraft Client" config
|
||||
|
||||

|
||||
|
||||
- In `Edit Configurations...` you need to select `baritone_launch` for `Use classpath of module:`.
|
||||
|
||||

|
||||
|
||||
## IntelliJ
|
||||
|
||||
- Navigate to the gradle tasks on the right tab as follows
|
||||
|
||||

|
||||
|
||||
- Double click on **build** to run it
|
||||
- depending on the minecraft version, you may need to run `setupDecompWorkspace` or `genIntellijRuns` in order to get everything working
|
@ -59,6 +59,10 @@ allprojects {
|
||||
}
|
||||
}
|
||||
mavenCentral()
|
||||
maven {
|
||||
name = 'babbaj-repo'
|
||||
url = 'https://babbaj.github.io/maven/'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
@ -72,6 +76,8 @@ allprojects {
|
||||
implementation "org.ow2.asm:asm:9.3"
|
||||
// The following line declares the yarn mappings you may select this one as well.
|
||||
// mappings "net.fabricmc:yarn:1.17.1+build.32:v2"
|
||||
//launchImplementation('dev.babbaj:nether-pathfinder:1.3.0')
|
||||
implementation 'dev.babbaj:nether-pathfinder:1.3.0'
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
|
@ -18,7 +18,6 @@
|
||||
package baritone.gradle.task;
|
||||
|
||||
import baritone.gradle.util.Determinizer;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.gradle.api.plugins.JavaPluginConvention;
|
||||
import org.gradle.api.tasks.Input;
|
||||
import org.gradle.api.tasks.TaskAction;
|
||||
@ -31,18 +30,17 @@ import xyz.wagyourtail.unimined.api.minecraft.EnvType;
|
||||
import xyz.wagyourtail.unimined.api.minecraft.MinecraftProvider;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 10/11/2018
|
||||
@ -63,16 +61,21 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
return extract;
|
||||
}
|
||||
|
||||
private List<String> requiredLibraries;
|
||||
|
||||
private File pathfinder;
|
||||
|
||||
@TaskAction
|
||||
protected void exec() throws Exception {
|
||||
super.doFirst();
|
||||
super.verifyArtifacts();
|
||||
|
||||
// "Haha brady why don't you make separate tasks"
|
||||
processArtifact();
|
||||
downloadProguard();
|
||||
extractProguard();
|
||||
generateConfigs();
|
||||
pathfinder = acquireDependencies().filter(file -> file.getName().contains("nether-pathfinder")).findAny().get();
|
||||
processArtifact();
|
||||
proguardApi();
|
||||
proguardStandalone();
|
||||
cleanup();
|
||||
@ -93,7 +96,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
Files.delete(this.artifactUnoptimizedPath);
|
||||
}
|
||||
|
||||
Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString());
|
||||
Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString(), Arrays.asList(pathfinder), false);
|
||||
}
|
||||
|
||||
private void downloadProguard() throws Exception {
|
||||
@ -118,8 +121,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
try {
|
||||
path = findJavaPathByGradleConfig();
|
||||
if (path != null) return path;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Unable to find java by javaCompile options");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -127,8 +129,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
try {
|
||||
path = findJavaByJavaHome();
|
||||
if (path != null) return path;
|
||||
}
|
||||
catch(Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
System.err.println("Unable to find java by JAVA_HOME");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
@ -136,30 +137,23 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
|
||||
path = findJavaByGradleCurrentRuntime();
|
||||
if (path != null) return path;
|
||||
|
||||
|
||||
throw new Exception("Unable to find java to determine ProGuard libraryjars. Please specify forkOptions.executable in javaCompile," +
|
||||
" JAVA_HOME environment variable, or make sure to run Gradle with the correct JDK (a v1.8 only)");
|
||||
}
|
||||
|
||||
private String findJavaByGradleCurrentRuntime() {
|
||||
String path = Jvm.current().getJavaExecutable().getAbsolutePath();
|
||||
|
||||
if (this.validateJavaVersion(path)) {
|
||||
System.out.println("Using Gradle's runtime Java for ProGuard");
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
System.out.println("Using Gradle's runtime Java for ProGuard");
|
||||
return path;
|
||||
}
|
||||
|
||||
private String findJavaByJavaHome() {
|
||||
final String javaHomeEnv = System.getenv("JAVA_HOME");
|
||||
if (javaHomeEnv != null) {
|
||||
|
||||
String path = Jvm.forHome(new File(javaHomeEnv)).getJavaExecutable().getAbsolutePath();
|
||||
if (this.validateJavaVersion(path)) {
|
||||
System.out.println("Detected Java path by JAVA_HOME");
|
||||
return path;
|
||||
}
|
||||
System.out.println("Detected Java path by JAVA_HOME");
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -175,19 +169,11 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
if (javacPath != null) {
|
||||
File javacFile = new File(javacPath);
|
||||
if (javacFile.exists()) {
|
||||
File[] maybeJava = javacFile.getParentFile().listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File dir, String name) {
|
||||
return name.equals("java");
|
||||
}
|
||||
});
|
||||
|
||||
File[] maybeJava = javacFile.getParentFile().listFiles((dir, name) -> name.equals("java"));
|
||||
if (maybeJava != null && maybeJava.length > 0) {
|
||||
String path = maybeJava[0].getAbsolutePath();
|
||||
if (this.validateJavaVersion(path)) {
|
||||
System.out.println("Detected Java path by forkOptions");
|
||||
return path;
|
||||
}
|
||||
System.out.println("Detected Java path by forkOptions");
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -210,7 +196,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
}
|
||||
|
||||
private void generateConfigs() throws Exception {
|
||||
Files.copy(getRootRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), REPLACE_EXISTING);
|
||||
Files.copy(getRootRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), StandardCopyOption.REPLACE_EXISTING);
|
||||
|
||||
// Setup the template that will be used to derive the API and Standalone configs
|
||||
List<String> template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST));
|
||||
@ -233,11 +219,11 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
{
|
||||
// Discover all of the libraries that we will need to acquire from gradle
|
||||
final Stream<File> dependencies = acquireDependencies()
|
||||
// remove MCP mapped jar, and nashorn
|
||||
.filter(f -> !f.toString().endsWith("-recomp.jar") && !f.getName().startsWith("nashorn") && !f.getName().startsWith("coremods"));
|
||||
// remove MCP mapped jar, and nashorn
|
||||
.filter(f -> !f.toString().endsWith("-recomp.jar") && !f.getName().startsWith("nashorn") && !f.getName().startsWith("coremods"));
|
||||
|
||||
libraries = dependencies
|
||||
.map(f -> isMcJar(f) ? mcJar : f);
|
||||
.map(f -> isMcJar(f) ? mcJar : f);
|
||||
}
|
||||
libraries.forEach(f -> {
|
||||
template.add(2, "-libraryjars '" + f + "'");
|
||||
@ -250,29 +236,48 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
api.add(2, "-printmapping " + new File(this.getRootRelativeFile(PROGUARD_MAPPING_DIR).toFile(), "mappings-" + addCompTypeFirst("api.txt")));
|
||||
|
||||
// API config doesn't require any changes from the changes that we made to the template
|
||||
Files.write(getTemporaryFile(compType+PROGUARD_API_CONFIG), api);
|
||||
Files.write(getTemporaryFile(compType + PROGUARD_API_CONFIG), api);
|
||||
|
||||
// For the Standalone config, don't keep the API package
|
||||
List<String> standalone = new ArrayList<>(template);
|
||||
standalone.removeIf(s -> s.contains("# this is the keep api"));
|
||||
standalone.add(2, "-printmapping " + new File(this.getRootRelativeFile(PROGUARD_MAPPING_DIR).toFile(), "mappings-" + addCompTypeFirst("standalone.txt")));
|
||||
Files.write(getTemporaryFile(compType+PROGUARD_STANDALONE_CONFIG), standalone);
|
||||
Files.write(getTemporaryFile(compType + PROGUARD_STANDALONE_CONFIG), standalone);
|
||||
}
|
||||
|
||||
private Stream<File> acquireDependencies() {
|
||||
return getProject().getConvention().getPlugin(JavaPluginConvention.class).getSourceSets().findByName("main").getCompileClasspath().getFiles()
|
||||
.stream()
|
||||
.filter(File::isFile);
|
||||
.stream()
|
||||
.filter(File::isFile);
|
||||
}
|
||||
|
||||
private void proguardApi() throws Exception {
|
||||
runProguard(getTemporaryFile(compType+PROGUARD_API_CONFIG));
|
||||
Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString());
|
||||
runProguard(getTemporaryFile(compType + PROGUARD_API_CONFIG));
|
||||
Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString(), Arrays.asList(pathfinder), false);
|
||||
}
|
||||
|
||||
private void proguardStandalone() throws Exception {
|
||||
runProguard(getTemporaryFile(compType+PROGUARD_STANDALONE_CONFIG));
|
||||
Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString());
|
||||
runProguard(getTemporaryFile(compType + PROGUARD_STANDALONE_CONFIG));
|
||||
Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString(), Arrays.asList(pathfinder), false);
|
||||
}
|
||||
|
||||
private static final class Pair<A, B> {
|
||||
public final A a;
|
||||
public final B b;
|
||||
|
||||
private Pair(final A a, final B b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pair{" +
|
||||
"a=" + this.a +
|
||||
", " +
|
||||
"b=" + this.b +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanup() {
|
||||
@ -285,9 +290,11 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
|
||||
public void setExtract(String extract) {
|
||||
this.extract = extract;
|
||||
}
|
||||
|
||||
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)) {
|
||||
@ -298,7 +305,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
Path workingDirectory = getTemporaryFile("");
|
||||
Path proguardJar = workingDirectory.relativize(getTemporaryFile(PROGUARD_JAR));
|
||||
config = workingDirectory.relativize(config);
|
||||
|
||||
|
||||
// Honestly, if you still have spaces in your path at this point, you're SOL.
|
||||
|
||||
Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString())
|
||||
@ -312,6 +319,7 @@ public class ProguardTask extends BaritoneGradleTask {
|
||||
// Halt the current thread until the process is complete, if the exit code isn't 0, throw an exception
|
||||
int exitCode = p.waitFor();
|
||||
if (exitCode != 0) {
|
||||
Thread.sleep(1000);
|
||||
throw new IllegalStateException("Proguard exited with code " + exitCode);
|
||||
}
|
||||
}
|
||||
|
@ -39,10 +39,11 @@ import java.util.stream.Collectors;
|
||||
*/
|
||||
public class Determinizer {
|
||||
|
||||
public static void determinize(String inputPath, String outputPath) throws IOException {
|
||||
public static void determinize(String inputPath, String outputPath, List<File> toInclude, boolean doForgeReplacementOfMetaInf) throws IOException {
|
||||
System.out.println("Running Determinizer");
|
||||
System.out.println(" Input path: " + inputPath);
|
||||
System.out.println(" Output path: " + outputPath);
|
||||
System.out.println(" Shade: " + toInclude);
|
||||
|
||||
try (
|
||||
JarFile jarFile = new JarFile(new File(inputPath));
|
||||
@ -64,14 +65,35 @@ public class Determinizer {
|
||||
clone.setTime(42069);
|
||||
jos.putNextEntry(clone);
|
||||
if (entry.getName().endsWith(".refmap.json")) {
|
||||
JsonObject object = new JsonParser().parse(new InputStreamReader(jarFile.getInputStream(entry))).getAsJsonObject();
|
||||
jos.write(writeSorted(object).getBytes());
|
||||
JsonElement json = new JsonParser().parse(new InputStreamReader(jarFile.getInputStream(entry)));
|
||||
jos.write(writeSorted(json).getBytes());
|
||||
} else if (entry.getName().equals("META-INF/MANIFEST.MF") && doForgeReplacementOfMetaInf) { // only replace for forge jar
|
||||
ByteArrayOutputStream cancer = new ByteArrayOutputStream();
|
||||
copy(jarFile.getInputStream(entry), cancer);
|
||||
String manifest = new String(cancer.toByteArray());
|
||||
if (!manifest.contains("baritone.launch.BaritoneTweaker")) {
|
||||
throw new IllegalStateException("unable to replace");
|
||||
}
|
||||
manifest = manifest.replace("baritone.launch.BaritoneTweaker", "org.spongepowered.asm.launch.MixinTweaker");
|
||||
jos.write(manifest.getBytes());
|
||||
} else {
|
||||
copy(jarFile.getInputStream(entry), jos);
|
||||
}
|
||||
}
|
||||
for (File file : toInclude) {
|
||||
try (JarFile mixin = new JarFile(file)) {
|
||||
for (JarEntry entry : mixin.stream().sorted(Comparator.comparing(JarEntry::getName)).collect(Collectors.toList())) {
|
||||
if (entry.getName().startsWith("META-INF") && !entry.getName().startsWith("META-INF/services")) {
|
||||
continue;
|
||||
}
|
||||
jos.putNextEntry(entry);
|
||||
copy(mixin.getInputStream(entry), jos);
|
||||
}
|
||||
}
|
||||
}
|
||||
jos.finish();
|
||||
}
|
||||
System.out.println("Done with determinizer");
|
||||
}
|
||||
|
||||
private static void copy(InputStream is, OutputStream os) throws IOException {
|
||||
@ -82,7 +104,7 @@ public class Determinizer {
|
||||
}
|
||||
}
|
||||
|
||||
private static String writeSorted(JsonObject in) throws IOException {
|
||||
private static String writeSorted(JsonElement in) throws IOException {
|
||||
StringWriter writer = new StringWriter();
|
||||
JsonWriter jw = new JsonWriter(writer);
|
||||
ORDERED_JSON_WRITER.write(jw, in);
|
||||
|
@ -26,6 +26,9 @@ archivesBaseName = archivesBaseName + "-fabric"
|
||||
|
||||
minecraft {
|
||||
fabric()
|
||||
runs.client = {
|
||||
jvmArgs.add("-XstartOnFirstThread")
|
||||
}
|
||||
}
|
||||
|
||||
configurations {
|
||||
|
2
gradlew
vendored
2
gradlew
vendored
@ -72,7 +72,7 @@ case "`uname`" in
|
||||
Darwin* )
|
||||
darwin=true
|
||||
;;
|
||||
MINGW* )
|
||||
MSYS* | MINGW* )
|
||||
msys=true
|
||||
;;
|
||||
NONSTOP* )
|
||||
|
2
scripts/proguard.pro
vendored
2
scripts/proguard.pro
vendored
@ -19,6 +19,8 @@
|
||||
-dontwarn module-info
|
||||
# we dont have forge
|
||||
-dontwarn baritone.launch.BaritoneForgeModXD
|
||||
# progard doesn't like signature polymorphism
|
||||
-dontwarn java.lang.invoke.MethodHandle
|
||||
|
||||
# please do not change the comment below
|
||||
-keep class baritone.api.** { *; } # this is the keep api
|
||||
|
@ -32,7 +32,7 @@ public final class BaritoneAPI {
|
||||
|
||||
static {
|
||||
settings = new Settings();
|
||||
SettingsUtil.readAndApply(settings);
|
||||
SettingsUtil.readAndApply(settings, SettingsUtil.SETTINGS_DEFAULT_NAME);
|
||||
|
||||
try {
|
||||
provider = (IBaritoneProvider) Class.forName("baritone.BaritoneProvider").newInstance();
|
||||
|
@ -88,6 +88,12 @@ public interface IBaritone {
|
||||
*/
|
||||
IGetToBlockProcess getGetToBlockProcess();
|
||||
|
||||
/**
|
||||
* @return The {@link IElytraProcess} instance
|
||||
* @see IElytraProcess
|
||||
*/
|
||||
IElytraProcess getElytraProcess();
|
||||
|
||||
/**
|
||||
* @return The {@link IWorldProvider} instance
|
||||
* @see IWorldProvider
|
||||
|
@ -21,9 +21,12 @@ import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.command.ICommand;
|
||||
import baritone.api.command.ICommandSystem;
|
||||
import baritone.api.schematic.ISchematicSystem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
|
||||
/**
|
||||
* Provides the present {@link IBaritone} instances, as well as non-baritone instance related APIs.
|
||||
@ -51,15 +54,13 @@ public interface IBaritoneProvider {
|
||||
List<IBaritone> getAllBaritones();
|
||||
|
||||
/**
|
||||
* Provides the {@link IBaritone} instance for a given {@link LocalPlayer}. This will likely be
|
||||
* replaced with or be overloaded in addition to {@code #getBaritoneForUser(IBaritoneUser)} when
|
||||
* {@code bot-system} is merged into {@code master}.
|
||||
* Provides the {@link IBaritone} instance for a given {@link LocalPlayer}.
|
||||
*
|
||||
* @param player The player
|
||||
* @return The {@link IBaritone} instance.
|
||||
*/
|
||||
default IBaritone getBaritoneForPlayer(LocalPlayer player) {
|
||||
for (IBaritone baritone : getAllBaritones()) {
|
||||
for (IBaritone baritone : this.getAllBaritones()) {
|
||||
if (Objects.equals(player, baritone.getPlayerContext().player())) {
|
||||
return baritone;
|
||||
}
|
||||
@ -67,6 +68,55 @@ public interface IBaritoneProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the {@link IBaritone} instance for a given {@link Minecraft}.
|
||||
*
|
||||
* @param minecraft The minecraft
|
||||
* @return The {@link IBaritone} instance.
|
||||
*/
|
||||
default IBaritone getBaritoneForMinecraft(Minecraft minecraft) {
|
||||
for (IBaritone baritone : this.getAllBaritones()) {
|
||||
if (Objects.equals(minecraft, baritone.getPlayerContext().minecraft())) {
|
||||
return baritone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the {@link IBaritone} instance for the player with the specified connection.
|
||||
*
|
||||
* @param connection The connection
|
||||
* @return The {@link IBaritone} instance.
|
||||
*/
|
||||
default IBaritone getBaritoneForConnection(ClientPacketListener connection) {
|
||||
for (IBaritone baritone : this.getAllBaritones()) {
|
||||
final LocalPlayer player = baritone.getPlayerContext().player();
|
||||
if (player != null && player.connection == connection) {
|
||||
return baritone;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and registers a new {@link IBaritone} instance using the specified {@link Minecraft}. The existing
|
||||
* instance is returned if already registered.
|
||||
*
|
||||
* @param minecraft The minecraft
|
||||
* @return The {@link IBaritone} instance
|
||||
*/
|
||||
IBaritone createBaritone(Minecraft minecraft);
|
||||
|
||||
/**
|
||||
* Destroys and removes the specified {@link IBaritone} instance. If the specified instance is the
|
||||
* {@link #getPrimaryBaritone() primary baritone}, this operation has no effect and will return {@code false}.
|
||||
*
|
||||
* @param baritone The baritone instance to remove
|
||||
* @return Whether the baritone instance was removed
|
||||
*/
|
||||
boolean destroyBaritone(IBaritone baritone);
|
||||
|
||||
/**
|
||||
* Returns the {@link IWorldScanner} instance. This is not a type returned by
|
||||
* {@link IBaritone} implementation, because it is not linked with {@link IBaritone}.
|
||||
|
@ -17,22 +17,30 @@
|
||||
|
||||
package baritone.api;
|
||||
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.NotificationHelper;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.TypeUtils;
|
||||
import baritone.api.utils.gui.BaritoneToast;
|
||||
import net.minecraft.client.GuiMessageTag;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Vec3i;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
|
||||
import java.awt.*;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@ -68,6 +76,16 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Boolean> allowInventory = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Wait this many ticks between InventoryBehavior moving inventory items
|
||||
*/
|
||||
public final Setting<Integer> ticksBetweenInventoryMoves = new Setting<>(1);
|
||||
|
||||
/**
|
||||
* Come to a halt before doing any inventory moves. Intended for anticheat such as 2b2t
|
||||
*/
|
||||
public final Setting<Boolean> inventoryMoveOnlyIfStationary = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Disable baritone's auto-tool at runtime, but still assume that another mod will provide auto tool functionality
|
||||
* <p>
|
||||
@ -609,6 +627,13 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Boolean> pruneRegionsFromRAM = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* The chunk packer queue can never grow to larger than this, if it does, the oldest chunks are discarded
|
||||
* <p>
|
||||
* The newest chunks are kept, so that if you're moving in a straight line quickly then stop, your immediate render distance is still included
|
||||
*/
|
||||
public final Setting<Integer> chunkPackerQueueMaxSize = new Setting<>(2000);
|
||||
|
||||
/**
|
||||
* Fill in blocks behind you
|
||||
*/
|
||||
@ -710,6 +735,37 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Boolean> freeLook = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Break and place blocks without having to force the client-sided rotations. Requires {@link #freeLook}.
|
||||
*/
|
||||
public final Setting<Boolean> blockFreeLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Automatically elytra fly without having to force the client-sided rotations.
|
||||
*/
|
||||
public final Setting<Boolean> elytraFreeLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Forces the client-sided yaw rotation to an average of the last {@link #smoothLookTicks} of server-sided rotations.
|
||||
*/
|
||||
public final Setting<Boolean> smoothLook = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Same as {@link #smoothLook} but for elytra flying.
|
||||
*/
|
||||
public final Setting<Boolean> elytraSmoothLook = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* The number of ticks to average across for {@link #smoothLook};
|
||||
*/
|
||||
public final Setting<Integer> smoothLookTicks = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* When true, the player will remain with its existing look direction as often as possible.
|
||||
* Although, in some cases this can get it stuck, hence this setting to disable that behavior.
|
||||
*/
|
||||
public final Setting<Boolean> remainWithExistingLookDirection = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Will cause some minor behavioral differences to ensure that Baritone works on anticheats.
|
||||
* <p>
|
||||
@ -772,6 +828,11 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Boolean> shortBaritonePrefix = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Use a modern message tag instead of a prefix when logging to chat
|
||||
*/
|
||||
public final Setting<Boolean> useMessageTag = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Echo commands to chat when they are run
|
||||
*/
|
||||
@ -845,6 +906,11 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Integer> minYLevelWhileMining = new Setting<>(0);
|
||||
|
||||
/**
|
||||
* Sets the maximum y level to mine ores at.
|
||||
*/
|
||||
public final Setting<Integer> maxYLevelWhileMining = new Setting<>(2031);
|
||||
|
||||
/**
|
||||
* This will only allow baritone to mine exposed ores, can be used to stop ore obfuscators on servers that use them.
|
||||
*/
|
||||
@ -1141,13 +1207,18 @@ public final class Settings {
|
||||
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
|
||||
* {@link Setting#value};
|
||||
*/
|
||||
public final Setting<Consumer<Component>> logger = new Setting<>(msg -> Minecraft.getInstance().gui.getChat().addMessage(msg));
|
||||
@JavaOnly
|
||||
public final Setting<Consumer<Component>> logger = new Setting<>((msg) -> {
|
||||
final GuiMessageTag tag = useMessageTag.value ? Helper.MESSAGE_TAG : null;
|
||||
Minecraft.getInstance().gui.getChat().addMessage(msg, null, tag);
|
||||
});
|
||||
|
||||
/**
|
||||
* The function that is called when Baritone will send a desktop notification. This function can be added to
|
||||
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
|
||||
* {@link Setting#value};
|
||||
*/
|
||||
@JavaOnly
|
||||
public final Setting<BiConsumer<String, Boolean>> notifier = new Setting<>(NotificationHelper::notify);
|
||||
|
||||
/**
|
||||
@ -1155,6 +1226,7 @@ public final class Settings {
|
||||
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
|
||||
* {@link Setting#value};
|
||||
*/
|
||||
@JavaOnly
|
||||
public final Setting<BiConsumer<Component, Component>> toaster = new Setting<>(BaritoneToast::addOrUpdate);
|
||||
|
||||
/**
|
||||
@ -1287,6 +1359,115 @@ public final class Settings {
|
||||
*/
|
||||
public final Setting<Boolean> notificationOnMineFail = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* The number of ticks of elytra movement to simulate while firework boost is not active. Higher values are
|
||||
* computationally more expensive.
|
||||
*/
|
||||
public final Setting<Integer> elytraSimulationTicks = new Setting<>(20);
|
||||
|
||||
/**
|
||||
* The maximum allowed deviation in pitch from a direct line-of-sight to the flight target. Higher values are
|
||||
* computationally more expensive.
|
||||
*/
|
||||
public final Setting<Integer> elytraPitchRange = new Setting<>(25);
|
||||
|
||||
/**
|
||||
* The minimum speed that the player can drop to (in blocks/tick) before a firework is automatically deployed.
|
||||
*/
|
||||
public final Setting<Double> elytraFireworkSpeed = new Setting<>(1.2);
|
||||
|
||||
/**
|
||||
* The delay after the player's position is set-back by the server that a firework may be automatically deployed.
|
||||
* Value is in ticks.
|
||||
*/
|
||||
public final Setting<Integer> elytraFireworkSetbackUseDelay = new Setting<>(15);
|
||||
|
||||
/**
|
||||
* The minimum padding value that is added to the player's hitbox when considering which point to fly to on the
|
||||
* path. High values can result in points not being considered which are otherwise safe to fly to. Low values can
|
||||
* result in flight paths which are extremely tight, and there's the possibility of crashing due to getting too low
|
||||
* to the ground.
|
||||
*/
|
||||
public final Setting<Double> elytraMinimumAvoidance = new Setting<>(0.2);
|
||||
|
||||
/**
|
||||
* If enabled, avoids using fireworks when descending along the flight path.
|
||||
*/
|
||||
public final Setting<Boolean> elytraConserveFireworks = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Renders the raytraces that are performed by the elytra fly calculation.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderRaytraces = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Renders the raytraces that are used in the hitbox part of the elytra fly calculation.
|
||||
* Requires {@link #elytraRenderRaytraces}.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderHitboxRaytraces = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Renders the best elytra flight path that was simulated each tick.
|
||||
*/
|
||||
public final Setting<Boolean> elytraRenderSimulation = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Automatically path to and jump off of ledges to initiate elytra flight when grounded.
|
||||
*/
|
||||
public final Setting<Boolean> elytraAutoJump = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* The seed used to generate chunks for long distance elytra path-finding in the nether.
|
||||
* Defaults to 2b2t's nether seed.
|
||||
*/
|
||||
public final Setting<Long> elytraNetherSeed = new Setting<>(146008555100680L);
|
||||
|
||||
/**
|
||||
* Whether nether-pathfinder should generate terrain based on {@link #elytraNetherSeed}.
|
||||
* If false all chunks that haven't been loaded are assumed to be air.
|
||||
*/
|
||||
public final Setting<Boolean> elytraPredictTerrain = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Automatically swap the current elytra with a new one when the durability gets too low
|
||||
*/
|
||||
public final Setting<Boolean> elytraAutoSwap = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* The minimum durability an elytra can have before being swapped
|
||||
*/
|
||||
public final Setting<Integer> elytraMinimumDurability = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* The minimum fireworks before landing early for safety
|
||||
*/
|
||||
public final Setting<Integer> elytraMinFireworksBeforeLanding = new Setting<>(5);
|
||||
|
||||
/**
|
||||
* Automatically land when elytra is almost out of durability, or almost out of fireworks
|
||||
*/
|
||||
public final Setting<Boolean> elytraAllowEmergencyLand = new Setting<>(true);
|
||||
|
||||
/**
|
||||
* Time between culling far away chunks from the nether pathfinder chunk cache
|
||||
*/
|
||||
public final Setting<Long> elytraTimeBetweenCacheCullSecs = new Setting<>(TimeUnit.MINUTES.toSeconds(3));
|
||||
|
||||
/**
|
||||
* Maximum distance chunks can be before being culled from the nether pathfinder chunk cache
|
||||
*/
|
||||
public final Setting<Integer> elytraCacheCullDistance = new Setting<>(5000);
|
||||
|
||||
/**
|
||||
* Should elytra consider nether brick a valid landing block
|
||||
*/
|
||||
public final Setting<Boolean> elytraAllowLandOnNetherFortress = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* Has the user read and understood the elytra terms and conditions
|
||||
*/
|
||||
public final Setting<Boolean> elytraTermsAccepted = new Setting<>(false);
|
||||
|
||||
/**
|
||||
* A map of lowercase setting field names to their respective setting
|
||||
*/
|
||||
@ -1304,6 +1485,7 @@ public final class Settings {
|
||||
public T value;
|
||||
public final T defaultValue;
|
||||
private String name;
|
||||
private boolean javaOnly;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Setting(T value) {
|
||||
@ -1312,6 +1494,7 @@ public final class Settings {
|
||||
}
|
||||
this.value = value;
|
||||
this.defaultValue = value;
|
||||
this.javaOnly = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1348,8 +1531,25 @@ public final class Settings {
|
||||
public final Type getType() {
|
||||
return settingTypes.get(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This should always be the same as whether the setting can be parsed from or serialized to a string; in other
|
||||
* words, the only way to modify it is by writing to {@link #value} programatically.
|
||||
*
|
||||
* @return {@code true} if the setting can not be set or read by the user
|
||||
*/
|
||||
public boolean isJavaOnly() {
|
||||
return javaOnly;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks a {@link Setting} field as being {@link Setting#isJavaOnly() Java-only}
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
private @interface JavaOnly {}
|
||||
|
||||
// here be dragons
|
||||
|
||||
Settings() {
|
||||
@ -1365,6 +1565,7 @@ public final class Settings {
|
||||
Setting<?> setting = (Setting<?>) field.get(this);
|
||||
String name = field.getName();
|
||||
setting.name = name;
|
||||
setting.javaOnly = field.isAnnotationPresent(JavaOnly.class);
|
||||
name = name.toLowerCase();
|
||||
if (tmpByName.containsKey(name)) {
|
||||
throw new IllegalStateException("Duplicate setting name");
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
package baritone.api.behavior;
|
||||
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.behavior.look.IAimProcessor;
|
||||
import baritone.api.utils.Rotation;
|
||||
|
||||
/**
|
||||
@ -26,14 +28,23 @@ import baritone.api.utils.Rotation;
|
||||
public interface ILookBehavior extends IBehavior {
|
||||
|
||||
/**
|
||||
* Updates the current {@link ILookBehavior} target to target
|
||||
* the specified rotations on the next tick. If force is {@code true},
|
||||
* then freeLook will be overriden and angles will be set regardless.
|
||||
* If any sort of block interaction is required, force should be {@code true},
|
||||
* otherwise, it should be {@code false};
|
||||
* Updates the current {@link ILookBehavior} target to target the specified rotations on the next tick. If any sort
|
||||
* of block interaction is required, {@code blockInteract} should be {@code true}. It is not guaranteed that the
|
||||
* rotations set by the caller will be the exact rotations expressed by the client (This is due to settings like
|
||||
* {@link Settings#randomLooking}). If the rotations produced by this behavior are required, then the
|
||||
* {@link #getAimProcessor() aim processor} should be used.
|
||||
*
|
||||
* @param rotation The target rotations
|
||||
* @param force Whether or not to "force" the rotations
|
||||
* @param rotation The target rotations
|
||||
* @param blockInteract Whether the target rotations are needed for a block interaction
|
||||
*/
|
||||
void updateTarget(Rotation rotation, boolean force);
|
||||
void updateTarget(Rotation rotation, boolean blockInteract);
|
||||
|
||||
/**
|
||||
* The aim processor instance for this {@link ILookBehavior}, which is responsible for applying additional,
|
||||
* deterministic transformations to the target rotation set by {@link #updateTarget}.
|
||||
*
|
||||
* @return The aim processor
|
||||
* @see IAimProcessor#fork
|
||||
*/
|
||||
IAimProcessor getAimProcessor();
|
||||
}
|
||||
|
45
src/api/java/baritone/api/behavior/look/IAimProcessor.java
Normal file
45
src/api/java/baritone/api/behavior/look/IAimProcessor.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* 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.behavior.look;
|
||||
|
||||
import baritone.api.utils.Rotation;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public interface IAimProcessor {
|
||||
|
||||
/**
|
||||
* Returns the actual rotation that will be used when the desired rotation is requested. The returned rotation
|
||||
* always reflects what would happen in the upcoming tick. In other words, it is a pure function, and no internal
|
||||
* state changes. If simulation of the rotation states beyond the next tick is required, then a
|
||||
* {@link IAimProcessor#fork fork} should be created.
|
||||
*
|
||||
* @param desired The desired rotation to set
|
||||
* @return The actual rotation
|
||||
*/
|
||||
Rotation peekRotation(Rotation desired);
|
||||
|
||||
/**
|
||||
* Returns a copy of this {@link IAimProcessor} which has its own internal state and is manually tickable.
|
||||
*
|
||||
* @return The forked processor
|
||||
* @see ITickableAimProcessor
|
||||
*/
|
||||
ITickableAimProcessor fork();
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.behavior.look;
|
||||
|
||||
import baritone.api.utils.Rotation;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public interface ITickableAimProcessor extends IAimProcessor {
|
||||
|
||||
/**
|
||||
* Advances the internal state of this aim processor by a single tick.
|
||||
*/
|
||||
void tick();
|
||||
|
||||
/**
|
||||
* Calls {@link #tick()} the specified number of times.
|
||||
*
|
||||
* @param ticks The number of calls
|
||||
*/
|
||||
void advance(int ticks);
|
||||
|
||||
/**
|
||||
* Returns the actual rotation as provided by {@link #peekRotation(Rotation)}, and then automatically advances the
|
||||
* internal state by one {@link #tick() tick}.
|
||||
*
|
||||
* @param rotation The desired rotation to set
|
||||
* @return The actual rotation
|
||||
*/
|
||||
Rotation nextRotation(Rotation rotation);
|
||||
}
|
@ -17,6 +17,8 @@
|
||||
|
||||
package baritone.api.cache;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 9/24/2018
|
||||
@ -29,4 +31,11 @@ public interface IWorldProvider {
|
||||
* @return The current world data
|
||||
*/
|
||||
IWorldData getCurrentWorld();
|
||||
|
||||
default void ifWorldLoaded(Consumer<IWorldData> callback) {
|
||||
final IWorldData currentWorld = this.getCurrentWorld();
|
||||
if (currentWorld != null) {
|
||||
callback.accept(currentWorld);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,11 +23,17 @@ import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum BlockById implements IDatatypeFor<Block> {
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* Matches (domain:)?name? where domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ respectively.
|
||||
*/
|
||||
private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?[a-z0-9/_.-]*");
|
||||
|
||||
@Override
|
||||
public Block get(IDatatypeContext ctx) throws CommandException {
|
||||
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
|
||||
@ -40,13 +46,19 @@ public enum BlockById implements IDatatypeFor<Block> {
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||
String arg = ctx.getConsumer().getString();
|
||||
|
||||
if (!PATTERN.matcher(arg).matches()) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
BuiltInRegistries.BLOCK.keySet()
|
||||
.stream()
|
||||
.map(Object::toString)
|
||||
)
|
||||
.filterPrefixNamespaced(ctx.getConsumer().getString())
|
||||
.filterPrefixNamespaced(arg)
|
||||
.sortAlphabetically()
|
||||
.stream();
|
||||
}
|
||||
|
43
src/api/java/baritone/api/command/datatypes/ForAxis.java
Normal file
43
src/api/java/baritone/api/command/datatypes/ForAxis.java
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.command.datatypes;
|
||||
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import net.minecraft.core.Direction;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum ForAxis implements IDatatypeFor<Direction.Axis> {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public Direction.Axis get(IDatatypeContext ctx) throws CommandException {
|
||||
return Direction.Axis.valueOf(ctx.getConsumer().getString().toUpperCase(Locale.US));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||
return new TabCompleteHelper()
|
||||
.append(Stream.of(Direction.Axis.values())
|
||||
.map(Direction.Axis::getName).map(String::toLowerCase))
|
||||
.filterPrefix(ctx.getConsumer().getString())
|
||||
.stream();
|
||||
}
|
||||
}
|
@ -18,20 +18,137 @@
|
||||
package baritone.api.command.datatypes;
|
||||
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import baritone.api.utils.BlockOptionalMeta;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum ForBlockOptionalMeta implements IDatatypeFor<BlockOptionalMeta> {
|
||||
INSTANCE;
|
||||
|
||||
/**
|
||||
* Matches (domain:)?name([(property=value)*])? but the input can be truncated at any position.
|
||||
* domain and name are [a-z0-9_.-]+ and [a-z0-9/_.-]+ because that's what mc 1.13+ accepts.
|
||||
* property and value use the same format as domain.
|
||||
*/
|
||||
// Good luck reading this.
|
||||
private static Pattern PATTERN = Pattern.compile("(?:[a-z0-9_.-]+:)?(?:[a-z0-9/_.-]+(?:\\[(?:(?:[a-z0-9_.-]+=[a-z0-9_.-]+,)*(?:[a-z0-9_.-]+(?:=(?:[a-z0-9_.-]+(?:\\])?)?)?)?|\\])?)?)?");
|
||||
|
||||
@Override
|
||||
public BlockOptionalMeta get(IDatatypeContext ctx) throws CommandException {
|
||||
return new BlockOptionalMeta(ctx.getConsumer().getString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(IDatatypeContext ctx) {
|
||||
return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE);
|
||||
public Stream<String> tabComplete(IDatatypeContext ctx) throws CommandException {
|
||||
String arg = ctx.getConsumer().peekString();
|
||||
|
||||
if (!PATTERN.matcher(arg).matches()) {
|
||||
// Invalid format; we can't complete this.
|
||||
ctx.getConsumer().getString();
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
if (arg.endsWith("]")) {
|
||||
// We are already done.
|
||||
ctx.getConsumer().getString();
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
if (!arg.contains("[")) {
|
||||
// no properties so we are completing the block id
|
||||
return ctx.getConsumer().tabCompleteDatatype(BlockById.INSTANCE);
|
||||
}
|
||||
|
||||
ctx.getConsumer().getString();
|
||||
|
||||
// destructuring assignment? Please?
|
||||
String blockId, properties;
|
||||
{
|
||||
String[] parts = splitLast(arg, '[');
|
||||
blockId = parts[0];
|
||||
properties = parts[1];
|
||||
}
|
||||
|
||||
Block block = BuiltInRegistries.BLOCK.getOptional(new ResourceLocation(blockId)).orElse(null);
|
||||
if (block == null) {
|
||||
// This block doesn't exist so there's no properties to complete.
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
String leadingProperties, lastProperty;
|
||||
{
|
||||
String[] parts = splitLast(properties, ',');
|
||||
leadingProperties = parts[0];
|
||||
lastProperty = parts[1];
|
||||
}
|
||||
|
||||
if (!lastProperty.contains("=")) {
|
||||
// The last property-value pair doesn't have a value yet so we are completing its name
|
||||
Set<String> usedProps = Stream.of(leadingProperties.split(","))
|
||||
.map(pair -> pair.split("=")[0])
|
||||
.collect(Collectors.toSet());
|
||||
|
||||
String prefix = arg.substring(0, arg.length() - lastProperty.length());
|
||||
return new TabCompleteHelper()
|
||||
.append(
|
||||
block.getStateDefinition()
|
||||
.getProperties()
|
||||
.stream()
|
||||
.map(Property::getName)
|
||||
)
|
||||
.filter(prop -> !usedProps.contains(prop))
|
||||
.filterPrefix(lastProperty)
|
||||
.sortAlphabetically()
|
||||
.map(prop -> prefix + prop)
|
||||
.stream();
|
||||
}
|
||||
|
||||
String lastName, lastValue;
|
||||
{
|
||||
String[] parts = splitLast(lastProperty, '=');
|
||||
lastName = parts[0];
|
||||
lastValue = parts[1];
|
||||
}
|
||||
|
||||
// We are completing the value of a property
|
||||
String prefix = arg.substring(0, arg.length() - lastValue.length());
|
||||
|
||||
Property<?> property = block.getStateDefinition().getProperty(lastName);
|
||||
if (property == null) {
|
||||
// The property does not exist so there's no values to complete
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
return new TabCompleteHelper()
|
||||
.append(getValues(property))
|
||||
.filterPrefix(lastValue)
|
||||
.sortAlphabetically()
|
||||
.map(val -> prefix + val)
|
||||
.stream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Always returns exactly two strings.
|
||||
* If the separator is not found the FIRST returned string is empty.
|
||||
*/
|
||||
private static String[] splitLast(String string, char chr) {
|
||||
int idx = string.lastIndexOf(chr);
|
||||
if (idx == -1) {
|
||||
return new String[]{"", string};
|
||||
}
|
||||
return new String[]{string.substring(0, idx), string.substring(idx + 1)};
|
||||
}
|
||||
|
||||
// this shouldn't need to be a separate method?
|
||||
private static <T extends Comparable<T>> Stream<String> getValues(Property<T> property) {
|
||||
return property.getPossibleValues().stream().map(property::getName);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,8 @@ package baritone.api.command.datatypes;
|
||||
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.utils.Helper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@ -30,8 +32,6 @@ import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.utils.Helper.HELPER;
|
||||
|
||||
public enum RelativeFile implements IDatatypePost<File, File> {
|
||||
INSTANCE;
|
||||
|
||||
@ -93,8 +93,13 @@ public enum RelativeFile implements IDatatypePost<File, File> {
|
||||
.filter(s -> !s.contains(" "));
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static File gameDir() {
|
||||
File gameDir = HELPER.mc.gameDirectory.getAbsoluteFile();
|
||||
return gameDir(Helper.mc);
|
||||
}
|
||||
|
||||
public static File gameDir(Minecraft mc) {
|
||||
File gameDir = mc.gameDirectory.getAbsoluteFile();
|
||||
if (gameDir.getName().equals(".")) {
|
||||
return gameDir.getParentFile();
|
||||
}
|
||||
|
@ -19,8 +19,8 @@ package baritone.api.command.exception;
|
||||
|
||||
import baritone.api.command.ICommand;
|
||||
import baritone.api.command.argument.ICommandArgument;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.ChatFormatting;
|
||||
|
||||
import static baritone.api.utils.Helper.HELPER;
|
||||
|
||||
@ -36,10 +36,6 @@ public class CommandUnhandledException extends RuntimeException implements IComm
|
||||
|
||||
@Override
|
||||
public void handle(ICommand command, List<ICommandArgument> args) {
|
||||
HELPER.logDirect("An unhandled exception occurred. " +
|
||||
"The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
|
||||
ChatFormatting.RED);
|
||||
|
||||
this.printStackTrace();
|
||||
HELPER.logUnhandledException(this);
|
||||
}
|
||||
}
|
||||
|
@ -252,7 +252,7 @@ public class TabCompleteHelper {
|
||||
public TabCompleteHelper addSettings() {
|
||||
return append(
|
||||
BaritoneAPI.getSettings().allSettings.stream()
|
||||
.filter(s -> !SettingsUtil.javaOnlySetting(s))
|
||||
.filter(s -> !s.isJavaOnly())
|
||||
.map(Settings.Setting::getName)
|
||||
.sorted(String.CASE_INSENSITIVE_ORDER)
|
||||
);
|
||||
|
47
src/api/java/baritone/api/event/events/BlockChangeEvent.java
Normal file
47
src/api/java/baritone/api/event/events/BlockChangeEvent.java
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.event.events;
|
||||
|
||||
import baritone.api.utils.Pair;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class BlockChangeEvent {
|
||||
|
||||
private final ChunkPos chunk;
|
||||
private final List<Pair<BlockPos, BlockState>> blocks;
|
||||
|
||||
public BlockChangeEvent(ChunkPos pos, List<Pair<BlockPos, BlockState>> blocks) {
|
||||
this.chunk = pos;
|
||||
this.blocks = blocks;
|
||||
}
|
||||
|
||||
public ChunkPos getChunkPos() {
|
||||
return this.chunk;
|
||||
}
|
||||
|
||||
public List<Pair<BlockPos, BlockState>> getBlocks() {
|
||||
return this.blocks;
|
||||
}
|
||||
}
|
@ -57,31 +57,38 @@ public final class ChunkEvent {
|
||||
/**
|
||||
* @return The state of the event
|
||||
*/
|
||||
public final EventState getState() {
|
||||
public EventState getState() {
|
||||
return this.state;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of chunk event that occurred;
|
||||
*/
|
||||
public final Type getType() {
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Chunk X position.
|
||||
*/
|
||||
public final int getX() {
|
||||
public int getX() {
|
||||
return this.x;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The Chunk Z position.
|
||||
*/
|
||||
public final int getZ() {
|
||||
public int getZ() {
|
||||
return this.z;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the event was fired after a chunk population
|
||||
*/
|
||||
public boolean isPostPopulate() {
|
||||
return this.state == EventState.POST && this.type.isPopulate();
|
||||
}
|
||||
|
||||
public enum Type {
|
||||
|
||||
/**
|
||||
@ -106,6 +113,10 @@ public final class ChunkEvent {
|
||||
* <p>
|
||||
* And it's a partial chunk
|
||||
*/
|
||||
POPULATE_PARTIAL
|
||||
POPULATE_PARTIAL;
|
||||
|
||||
public final boolean isPopulate() {
|
||||
return this == POPULATE_FULL || this == POPULATE_PARTIAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.event.events;
|
||||
|
||||
import baritone.api.utils.Rotation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
@ -32,14 +33,27 @@ public final class RotationMoveEvent {
|
||||
*/
|
||||
private final Type type;
|
||||
|
||||
private final Rotation original;
|
||||
|
||||
/**
|
||||
* The yaw rotation
|
||||
*/
|
||||
private float yaw;
|
||||
|
||||
public RotationMoveEvent(Type type, float yaw) {
|
||||
/**
|
||||
* The pitch rotation
|
||||
*/
|
||||
private float pitch;
|
||||
|
||||
public RotationMoveEvent(Type type, float yaw, float pitch) {
|
||||
this.type = type;
|
||||
this.original = new Rotation(yaw, pitch);
|
||||
this.yaw = yaw;
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
public Rotation getOriginal() {
|
||||
return this.original;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -47,21 +61,37 @@ public final class RotationMoveEvent {
|
||||
*
|
||||
* @param yaw Yaw rotation
|
||||
*/
|
||||
public final void setYaw(float yaw) {
|
||||
public void setYaw(float yaw) {
|
||||
this.yaw = yaw;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The yaw rotation
|
||||
*/
|
||||
public final float getYaw() {
|
||||
public float getYaw() {
|
||||
return this.yaw;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the pitch movement rotation
|
||||
*
|
||||
* @param pitch Pitch rotation
|
||||
*/
|
||||
public void setPitch(float pitch) {
|
||||
this.pitch = pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The pitch rotation
|
||||
*/
|
||||
public float getPitch() {
|
||||
return pitch;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The type of the event
|
||||
*/
|
||||
public final Type getType() {
|
||||
public Type getType() {
|
||||
return this.type;
|
||||
}
|
||||
|
||||
|
@ -18,9 +18,18 @@
|
||||
package baritone.api.event.events;
|
||||
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
/**
|
||||
* Called on and after each game tick of the primary {@link Minecraft} instance and dispatched to all Baritone
|
||||
* instances.
|
||||
* <p>
|
||||
* When {@link #state} is {@link EventState#PRE}, the event is being called just prior to when the current in-game
|
||||
* screen is ticked. When {@link #state} is {@link EventState#POST}, the event is being called at the very end
|
||||
* of the {@link Minecraft#runTick()} method.
|
||||
*/
|
||||
public final class TickEvent {
|
||||
|
||||
private static int overallTickCount;
|
||||
|
@ -33,6 +33,9 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
||||
@Override
|
||||
default void onTick(TickEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onPostTick(TickEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onPlayerUpdate(PlayerUpdateEvent event) {}
|
||||
|
||||
@ -45,6 +48,9 @@ public interface AbstractGameEventListener extends IGameEventListener {
|
||||
@Override
|
||||
default void onChunkEvent(ChunkEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onBlockChange(BlockChangeEvent event) {}
|
||||
|
||||
@Override
|
||||
default void onRenderPass(RenderEvent event) {}
|
||||
|
||||
|
@ -40,6 +40,14 @@ public interface IGameEventListener {
|
||||
*/
|
||||
void onTick(TickEvent event);
|
||||
|
||||
/**
|
||||
* Run once per game tick after the tick is completed
|
||||
*
|
||||
* @param event The event
|
||||
* @see Minecraft#runTick()
|
||||
*/
|
||||
void onPostTick(TickEvent event);
|
||||
|
||||
/**
|
||||
* Run once per game tick from before and after the player rotation is sent to the server.
|
||||
*
|
||||
@ -70,6 +78,13 @@ public interface IGameEventListener {
|
||||
*/
|
||||
void onChunkEvent(ChunkEvent event);
|
||||
|
||||
/**
|
||||
* Runs after a single or multi block change packet is received and processed.
|
||||
*
|
||||
* @param event The event
|
||||
*/
|
||||
void onBlockChange(BlockChangeEvent event);
|
||||
|
||||
/**
|
||||
* Runs once per world render pass.
|
||||
*
|
||||
|
@ -42,6 +42,16 @@ public class GoalAxis implements Goal {
|
||||
return flatAxisDistance * BaritoneAPI.getSettings().costHeuristic.value + GoalYLevel.calculate(BaritoneAPI.getSettings().axisHeight.value, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return o.getClass() == GoalAxis.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 201385781;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GoalAxis";
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -66,6 +67,26 @@ public class GoalBlock implements Goal, IGoalRenderPos {
|
||||
return calculate(xDiff, yDiff, zDiff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalBlock goal = (GoalBlock) o;
|
||||
return x == goal.x
|
||||
&& y == goal.y
|
||||
&& z == goal.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) BetterBlockPos.longHash(x, y, z) * 905165533;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -67,6 +67,24 @@ public class GoalComposite implements Goal {
|
||||
return min;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalComposite goal = (GoalComposite) o;
|
||||
return Arrays.equals(goals, goal.goals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(goals);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "GoalComposite" + Arrays.toString(goals);
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -60,6 +61,26 @@ public class GoalGetToBlock implements Goal, IGoalRenderPos {
|
||||
return GoalBlock.calculate(xDiff, yDiff < 0 ? yDiff + 1 : yDiff, zDiff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalGetToBlock goal = (GoalGetToBlock) o;
|
||||
return x == goal.x
|
||||
&& y == goal.y
|
||||
&& z == goal.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) BetterBlockPos.longHash(x, y, z) * -49639096;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -17,6 +17,8 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Invert any goal.
|
||||
* <p>
|
||||
@ -50,6 +52,24 @@ public class GoalInverted implements Goal {
|
||||
return Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalInverted goal = (GoalInverted) o;
|
||||
return Objects.equals(origin, goal.origin);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return origin.hashCode() * 495796690;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("GoalInverted{%s}", origin.toString());
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import it.unimi.dsi.fastutil.doubles.DoubleIterator;
|
||||
@ -86,6 +87,27 @@ public class GoalNear implements Goal, IGoalRenderPos {
|
||||
return new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalNear goal = (GoalNear) o;
|
||||
return x == goal.x
|
||||
&& y == goal.y
|
||||
&& z == goal.z
|
||||
&& rangeSq == goal.rangeSq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) BetterBlockPos.longHash(x, y, z) + rangeSq;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -23,6 +23,7 @@ import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Useful for automated combat (retreating specifically)
|
||||
@ -124,6 +125,29 @@ public class GoalRunAway implements Goal {
|
||||
return maxInside;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalRunAway goal = (GoalRunAway) o;
|
||||
return distanceSq == goal.distanceSq
|
||||
&& Arrays.equals(from, goal.from)
|
||||
&& Objects.equals(maintainY, goal.maintainY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = Arrays.hashCode(from);
|
||||
hash = hash * 1196803141 + distanceSq;
|
||||
hash = hash * -2053788840 + maintainY;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
if (maintainY != null) {
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -69,6 +70,31 @@ public class GoalStrictDirection implements Goal {
|
||||
return Double.NEGATIVE_INFINITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalStrictDirection goal = (GoalStrictDirection) o;
|
||||
return x == goal.x
|
||||
&& y == goal.y
|
||||
&& z == goal.z
|
||||
&& dx == goal.dx
|
||||
&& dz == goal.dz;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = (int) BetterBlockPos.longHash(x, y, z);
|
||||
hash = hash * 630627507 + dx;
|
||||
hash = hash * -283028380 + dz;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
package baritone.api.pathing.goals;
|
||||
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.api.utils.interfaces.IGoalRenderPos;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -72,6 +73,26 @@ public class GoalTwoBlocks implements Goal, IGoalRenderPos {
|
||||
return new BlockPos(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalTwoBlocks goal = (GoalTwoBlocks) o;
|
||||
return x == goal.x
|
||||
&& y == goal.y
|
||||
&& z == goal.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (int) BetterBlockPos.longHash(x, y, z) * 516508351;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -64,6 +64,27 @@ public class GoalXZ implements Goal {
|
||||
return calculate(xDiff, zDiff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalXZ goal = (GoalXZ) o;
|
||||
return x == goal.x && z == goal.z;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = 1791873246;
|
||||
hash = hash * 222601791 + x;
|
||||
hash = hash * -1331679453 + z;
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -58,6 +58,24 @@ public class GoalYLevel implements Goal, ActionCosts {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || getClass() != o.getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
GoalYLevel goal = (GoalYLevel) o;
|
||||
return level == goal.level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return level * 1271009915;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(
|
||||
|
@ -50,6 +50,7 @@ public interface IBuilderProcess extends IBaritoneProcess {
|
||||
*/
|
||||
boolean build(String name, File schematic, Vec3i origin);
|
||||
|
||||
@Deprecated
|
||||
default boolean build(String schematicFile, BlockPos origin) {
|
||||
File file = new File(new File(Minecraft.getInstance().gameDirectory, "schematics"), schematicFile);
|
||||
return build(schematicFile, file, origin);
|
||||
|
@ -38,6 +38,11 @@ public interface ICustomGoalProcess extends IBaritoneProcess {
|
||||
*/
|
||||
Goal getGoal();
|
||||
|
||||
/**
|
||||
* @return The most recent set goal, which doesn't invalidate upon {@link #onLostControl()}
|
||||
*/
|
||||
Goal mostRecentGoal();
|
||||
|
||||
/**
|
||||
* Sets the goal and begins the path execution.
|
||||
*
|
||||
|
50
src/api/java/baritone/api/process/IElytraProcess.java
Normal file
50
src/api/java/baritone/api/process/IElytraProcess.java
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.process;
|
||||
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public interface IElytraProcess extends IBaritoneProcess {
|
||||
|
||||
void repackChunks();
|
||||
|
||||
/**
|
||||
* @return Where it is currently flying to, null if not active
|
||||
*/
|
||||
BlockPos currentDestination();
|
||||
|
||||
void pathTo(BlockPos destination);
|
||||
|
||||
void pathTo(Goal destination);
|
||||
|
||||
/**
|
||||
* Resets the state of the process but will maintain the same destination and will try to keep flying
|
||||
*/
|
||||
void resetState();
|
||||
|
||||
/**
|
||||
* @return {@code true} if the native library loaded and elytra is actually usable
|
||||
*/
|
||||
boolean isLoaded();
|
||||
|
||||
/*
|
||||
* FOR INTERNAL USE ONLY. MAY BE REMOVED AT ANY TIME.
|
||||
*/
|
||||
boolean isSafeToCancel();
|
||||
}
|
@ -56,5 +56,10 @@ public enum PathingCommandType {
|
||||
/**
|
||||
* Go and ask the next process what to do
|
||||
*/
|
||||
DEFER
|
||||
DEFER,
|
||||
|
||||
/**
|
||||
* Sets the goal and calculates a path, but pauses instead of immediately starting the path.
|
||||
*/
|
||||
SET_GOAL_AND_PAUSE
|
||||
}
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
package baritone.api.schematic;
|
||||
|
||||
import java.util.List;
|
||||
import baritone.api.schematic.mask.Mask;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class MaskSchematic extends AbstractSchematic {
|
||||
|
||||
private final ISchematic schematic;
|
||||
@ -40,4 +42,14 @@ public abstract class MaskSchematic extends AbstractSchematic {
|
||||
public BlockState desiredState(int x, int y, int z, BlockState current, List<BlockState> approxPlaceable) {
|
||||
return schematic.desiredState(x, y, z, current, approxPlaceable);
|
||||
}
|
||||
|
||||
public static MaskSchematic create(ISchematic schematic, Mask function) {
|
||||
return new MaskSchematic(schematic) {
|
||||
|
||||
@Override
|
||||
protected boolean partOfMask(int x, int y, int z, BlockState currentState) {
|
||||
return function.partOfMask(x, y, z, currentState);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
49
src/api/java/baritone/api/schematic/mask/AbstractMask.java
Normal file
49
src/api/java/baritone/api/schematic/mask/AbstractMask.java
Normal file
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.schematic.mask;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public abstract class AbstractMask implements Mask {
|
||||
|
||||
private final int widthX;
|
||||
private final int heightY;
|
||||
private final int lengthZ;
|
||||
|
||||
public AbstractMask(int widthX, int heightY, int lengthZ) {
|
||||
this.widthX = widthX;
|
||||
this.heightY = heightY;
|
||||
this.lengthZ = lengthZ;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int widthX() {
|
||||
return this.widthX;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int heightY() {
|
||||
return this.heightY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int lengthZ() {
|
||||
return this.lengthZ;
|
||||
}
|
||||
}
|
60
src/api/java/baritone/api/schematic/mask/Mask.java
Normal file
60
src/api/java/baritone/api/schematic/mask/Mask.java
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.schematic.mask;
|
||||
|
||||
import baritone.api.schematic.mask.operator.BinaryOperatorMask;
|
||||
import baritone.api.schematic.mask.operator.NotMask;
|
||||
import baritone.api.utils.BooleanBinaryOperators;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public interface Mask {
|
||||
|
||||
/**
|
||||
* @param x The relative x position of the block
|
||||
* @param y The relative y position of the block
|
||||
* @param z The relative z position of the block
|
||||
* @param currentState The current state of that block in the world, may be {@code null}
|
||||
* @return Whether the given position is included in this mask
|
||||
*/
|
||||
boolean partOfMask(int x, int y, int z, BlockState currentState);
|
||||
|
||||
int widthX();
|
||||
|
||||
int heightY();
|
||||
|
||||
int lengthZ();
|
||||
|
||||
default Mask not() {
|
||||
return new NotMask(this);
|
||||
}
|
||||
|
||||
default Mask union(Mask other) {
|
||||
return new BinaryOperatorMask(this, other, BooleanBinaryOperators.OR);
|
||||
}
|
||||
|
||||
default Mask intersection(Mask other) {
|
||||
return new BinaryOperatorMask(this, other, BooleanBinaryOperators.AND);
|
||||
}
|
||||
|
||||
default Mask xor(Mask other) {
|
||||
return new BinaryOperatorMask(this, other, BooleanBinaryOperators.XOR);
|
||||
}
|
||||
}
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.schematic.mask;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
final class PreComputedMask extends AbstractMask implements StaticMask {
|
||||
|
||||
private final boolean[][][] mask;
|
||||
|
||||
public PreComputedMask(StaticMask mask) {
|
||||
super(mask.widthX(), mask.heightY(), mask.lengthZ());
|
||||
|
||||
this.mask = new boolean[this.heightY()][this.lengthZ()][this.widthX()];
|
||||
for (int y = 0; y < this.heightY(); y++) {
|
||||
for (int z = 0; z < this.lengthZ(); z++) {
|
||||
for (int x = 0; x < this.widthX(); x++) {
|
||||
this.mask[y][z][x] = mask.partOfMask(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z) {
|
||||
return this.mask[y][z][x];
|
||||
}
|
||||
}
|
82
src/api/java/baritone/api/schematic/mask/StaticMask.java
Normal file
82
src/api/java/baritone/api/schematic/mask/StaticMask.java
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.schematic.mask;
|
||||
|
||||
import baritone.api.schematic.mask.operator.BinaryOperatorMask;
|
||||
import baritone.api.schematic.mask.operator.NotMask;
|
||||
import baritone.api.utils.BooleanBinaryOperators;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* A mask that is context-free. In other words, it doesn't require the current block state to determine if a relative
|
||||
* position is a part of the mask.
|
||||
*
|
||||
* @author Brady
|
||||
*/
|
||||
public interface StaticMask extends Mask {
|
||||
|
||||
/**
|
||||
* Determines if a given relative coordinate is included in this mask, without the need for the current block state.
|
||||
*
|
||||
* @param x The relative x position of the block
|
||||
* @param y The relative y position of the block
|
||||
* @param z The relative z position of the block
|
||||
* @return Whether the given position is included in this mask
|
||||
*/
|
||||
boolean partOfMask(int x, int y, int z);
|
||||
|
||||
/**
|
||||
* Implements the parent {@link Mask#partOfMask partOfMask function} by calling the static function
|
||||
* provided in this functional interface without needing the {@link BlockState} argument. This {@code default}
|
||||
* implementation should <b><u>NOT</u></b> be overriden.
|
||||
*
|
||||
* @param x The relative x position of the block
|
||||
* @param y The relative y position of the block
|
||||
* @param z The relative z position of the block
|
||||
* @param currentState The current state of that block in the world, may be {@code null}
|
||||
* @return Whether the given position is included in this mask
|
||||
*/
|
||||
@Override
|
||||
default boolean partOfMask(int x, int y, int z, BlockState currentState) {
|
||||
return this.partOfMask(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
default StaticMask not() {
|
||||
return new NotMask.Static(this);
|
||||
}
|
||||
|
||||
default StaticMask union(StaticMask other) {
|
||||
return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.OR);
|
||||
}
|
||||
|
||||
default StaticMask intersection(StaticMask other) {
|
||||
return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.AND);
|
||||
}
|
||||
|
||||
default StaticMask xor(StaticMask other) {
|
||||
return new BinaryOperatorMask.Static(this, other, BooleanBinaryOperators.XOR);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pre-computed mask using {@code this} function, with the specified size parameters.
|
||||
*/
|
||||
default StaticMask compute() {
|
||||
return new PreComputedMask(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.schematic.mask.operator;
|
||||
|
||||
import baritone.api.schematic.mask.AbstractMask;
|
||||
import baritone.api.schematic.mask.Mask;
|
||||
import baritone.api.schematic.mask.StaticMask;
|
||||
import baritone.api.utils.BooleanBinaryOperator;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class BinaryOperatorMask extends AbstractMask {
|
||||
|
||||
private final Mask a;
|
||||
private final Mask b;
|
||||
private final BooleanBinaryOperator operator;
|
||||
|
||||
public BinaryOperatorMask(Mask a, Mask b, BooleanBinaryOperator operator) {
|
||||
super(Math.max(a.widthX(), b.widthX()), Math.max(a.heightY(), b.heightY()), Math.max(a.lengthZ(), b.lengthZ()));
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z, BlockState currentState) {
|
||||
return this.operator.applyAsBoolean(
|
||||
partOfMask(a, x, y, z, currentState),
|
||||
partOfMask(b, x, y, z, currentState)
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean partOfMask(Mask mask, int x, int y, int z, BlockState currentState) {
|
||||
return x < mask.widthX() && y < mask.heightY() && z < mask.lengthZ() && mask.partOfMask(x, y, z, currentState);
|
||||
}
|
||||
|
||||
public static final class Static extends AbstractMask implements StaticMask {
|
||||
|
||||
private final StaticMask a;
|
||||
private final StaticMask b;
|
||||
private final BooleanBinaryOperator operator;
|
||||
|
||||
public Static(StaticMask a, StaticMask b, BooleanBinaryOperator operator) {
|
||||
super(Math.max(a.widthX(), b.widthX()), Math.max(a.heightY(), b.heightY()), Math.max(a.lengthZ(), b.lengthZ()));
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
this.operator = operator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z) {
|
||||
return this.operator.applyAsBoolean(
|
||||
partOfMask(a, x, y, z),
|
||||
partOfMask(b, x, y, z)
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean partOfMask(StaticMask mask, int x, int y, int z) {
|
||||
return x < mask.widthX() && y < mask.heightY() && z < mask.lengthZ() && mask.partOfMask(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.schematic.mask.operator;
|
||||
|
||||
import baritone.api.schematic.mask.AbstractMask;
|
||||
import baritone.api.schematic.mask.Mask;
|
||||
import baritone.api.schematic.mask.StaticMask;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class NotMask extends AbstractMask {
|
||||
|
||||
private final Mask source;
|
||||
|
||||
public NotMask(Mask source) {
|
||||
super(source.widthX(), source.heightY(), source.lengthZ());
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z, BlockState currentState) {
|
||||
return !this.source.partOfMask(x, y, z, currentState);
|
||||
}
|
||||
|
||||
public static final class Static extends AbstractMask implements StaticMask {
|
||||
|
||||
private final StaticMask source;
|
||||
|
||||
public Static(StaticMask source) {
|
||||
super(source.widthX(), source.heightY(), source.lengthZ());
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z) {
|
||||
return !this.source.partOfMask(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* This file is part of Baritone.
|
||||
*
|
||||
* Baritone is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU 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.schematic.mask.shape;
|
||||
|
||||
import baritone.api.schematic.mask.AbstractMask;
|
||||
import baritone.api.schematic.mask.StaticMask;
|
||||
import net.minecraft.core.Direction;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class CylinderMask extends AbstractMask implements StaticMask {
|
||||
|
||||
private final double centerA;
|
||||
private final double centerB;
|
||||
private final double radiusSqA;
|
||||
private final double radiusSqB;
|
||||
private final boolean filled;
|
||||
private final Direction.Axis alignment;
|
||||
|
||||
public CylinderMask(int widthX, int heightY, int lengthZ, boolean filled, Direction.Axis alignment) {
|
||||
super(widthX, heightY, lengthZ);
|
||||
this.centerA = this.getA(widthX, heightY, alignment) / 2.0;
|
||||
this.centerB = this.getB(heightY, lengthZ, alignment) / 2.0;
|
||||
this.radiusSqA = (this.centerA - 1) * (this.centerA - 1);
|
||||
this.radiusSqB = (this.centerB - 1) * (this.centerB - 1);
|
||||
this.filled = filled;
|
||||
this.alignment = alignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z) {
|
||||
double da = Math.abs((this.getA(x, y, this.alignment) + 0.5) - this.centerA);
|
||||
double db = Math.abs((this.getB(y, z, this.alignment) + 0.5) - this.centerB);
|
||||
if (this.outside(da, db)) {
|
||||
return false;
|
||||
}
|
||||
return this.filled
|
||||
|| this.outside(da + 1, db)
|
||||
|| this.outside(da, db + 1);
|
||||
}
|
||||
|
||||
private boolean outside(double da, double db) {
|
||||
return da * da / this.radiusSqA + db * db / this.radiusSqB > 1;
|
||||
}
|
||||
|
||||
private static int getA(int x, int y, Direction.Axis alignment) {
|
||||
return alignment == Direction.Axis.X ? y : x;
|
||||
}
|
||||
|
||||
private static int getB(int y, int z, Direction.Axis alignment) {
|
||||
return alignment == Direction.Axis.Z ? y : z;
|
||||
}
|
||||
}
|
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.schematic.mask.shape;
|
||||
|
||||
import baritone.api.schematic.mask.AbstractMask;
|
||||
import baritone.api.schematic.mask.StaticMask;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class SphereMask extends AbstractMask implements StaticMask {
|
||||
|
||||
private final double centerX;
|
||||
private final double centerY;
|
||||
private final double centerZ;
|
||||
private final double radiusSqX;
|
||||
private final double radiusSqY;
|
||||
private final double radiusSqZ;
|
||||
private final boolean filled;
|
||||
|
||||
public SphereMask(int widthX, int heightY, int lengthZ, boolean filled) {
|
||||
super(widthX, heightY, lengthZ);
|
||||
this.centerX = widthX / 2.0;
|
||||
this.centerY = heightY / 2.0;
|
||||
this.centerZ = lengthZ / 2.0;
|
||||
this.radiusSqX = this.centerX * this.centerX;
|
||||
this.radiusSqY = this.centerY * this.centerY;
|
||||
this.radiusSqZ = this.centerZ * this.centerZ;
|
||||
this.filled = filled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean partOfMask(int x, int y, int z) {
|
||||
double dx = Math.abs((x + 0.5) - this.centerX);
|
||||
double dy = Math.abs((y + 0.5) - this.centerY);
|
||||
double dz = Math.abs((z + 0.5) - this.centerZ);
|
||||
if (this.outside(dx, dy, dz)) {
|
||||
return false;
|
||||
}
|
||||
return this.filled
|
||||
|| this.outside(dx + 1, dy, dz)
|
||||
|| this.outside(dx, dy + 1, dz)
|
||||
|| this.outside(dx, dy, dz + 1);
|
||||
}
|
||||
|
||||
private boolean outside(double dx, double dy, double dz) {
|
||||
return dx * dx / this.radiusSqX + dy * dy / this.radiusSqY + dz * dz / this.radiusSqZ > 1;
|
||||
}
|
||||
}
|
@ -34,6 +34,15 @@ import net.minecraft.util.Mth;
|
||||
*/
|
||||
public final class BetterBlockPos extends BlockPos {
|
||||
|
||||
private static final int NUM_X_BITS = 26;
|
||||
private static final int NUM_Z_BITS = NUM_X_BITS;
|
||||
private static final int NUM_Y_BITS = 64 - NUM_X_BITS - NUM_Z_BITS;
|
||||
private static final int Y_SHIFT = NUM_Z_BITS;
|
||||
private static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS;
|
||||
private static final long X_MASK = (1L << NUM_X_BITS) - 1L;
|
||||
private static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
|
||||
private static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
|
||||
|
||||
public static final BetterBlockPos ORIGIN = new BetterBlockPos(0, 0, 0);
|
||||
|
||||
public final int x;
|
||||
@ -201,6 +210,20 @@ public final class BetterBlockPos extends BlockPos {
|
||||
return amt == 0 ? this : new BetterBlockPos(x - amt, y, z);
|
||||
}
|
||||
|
||||
public double distanceSq(final BetterBlockPos to) {
|
||||
double dx = (double) this.x - to.x;
|
||||
double dy = (double) this.y - to.y;
|
||||
double dz = (double) this.z - to.z;
|
||||
return dx * dx + dy * dy + dz * dz;
|
||||
}
|
||||
|
||||
public double distanceTo(final BetterBlockPos to) {
|
||||
double dx = (double) this.x - to.x;
|
||||
double dy = (double) this.y - to.y;
|
||||
double dz = (double) this.z - to.z;
|
||||
return Math.sqrt(dx * dx + dy * dy + dz * dz);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public String toString() {
|
||||
@ -211,4 +234,15 @@ public final class BetterBlockPos extends BlockPos {
|
||||
SettingsUtil.maybeCensor(z)
|
||||
);
|
||||
}
|
||||
|
||||
public static long serializeToLong(final int x, final int y, final int z) {
|
||||
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK);
|
||||
}
|
||||
|
||||
public static BetterBlockPos deserializeFromLong(final long serialized) {
|
||||
final int x = (int) (serialized << 64 - X_SHIFT - NUM_X_BITS >> 64 - NUM_X_BITS);
|
||||
final int y = (int) (serialized << 64 - Y_SHIFT - NUM_Y_BITS >> 64 - NUM_Y_BITS);
|
||||
final int z = (int) (serialized << 64 - NUM_Z_BITS >> 64 - NUM_Z_BITS);
|
||||
return new BetterBlockPos(x, y, z);
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
package baritone.api.utils;
|
||||
|
||||
import baritone.api.utils.accessor.IItemStack;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import io.netty.util.concurrent.ThreadPerTaskExecutor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
@ -27,11 +28,11 @@ import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.server.packs.*;
|
||||
import net.minecraft.server.packs.PackType;
|
||||
import net.minecraft.server.packs.VanillaPackResources;
|
||||
import net.minecraft.server.packs.repository.ServerPacksSource;
|
||||
import net.minecraft.server.packs.resources.MultiPackResourceManager;
|
||||
import net.minecraft.server.packs.resources.ReloadableResourceManager;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.util.Unit;
|
||||
import net.minecraft.world.RandomSequences;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
@ -41,6 +42,7 @@ import net.minecraft.world.level.CustomSpawner;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.block.state.properties.Property;
|
||||
import net.minecraft.world.level.dimension.LevelStem;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import net.minecraft.world.level.storage.ServerLevelData;
|
||||
@ -60,44 +62,80 @@ import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.regex.MatchResult;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public final class BlockOptionalMeta {
|
||||
// id or id[] or id[properties] where id and properties are any text with at least one character
|
||||
private static final Pattern PATTERN = Pattern.compile("^(?<id>.+?)(?:\\[(?<properties>.+?)?\\])?$");
|
||||
|
||||
private final Block block;
|
||||
private final String propertiesDescription; // exists so toString() can return something more useful than a list of all blockstates
|
||||
private final Set<BlockState> blockstates;
|
||||
private final ImmutableSet<Integer> stateHashes;
|
||||
private final ImmutableSet<Integer> stackHashes;
|
||||
private static final Pattern pattern = Pattern.compile("^(.+?)(?::(\\d+))?$");
|
||||
private static LootDataManager lootTables;
|
||||
|
||||
private static Map<Block, List<Item>> drops = new HashMap<>();
|
||||
|
||||
public BlockOptionalMeta(@Nonnull Block block) {
|
||||
this.block = block;
|
||||
this.blockstates = getStates(block);
|
||||
this.propertiesDescription = "{}";
|
||||
this.blockstates = getStates(block, Collections.emptyMap());
|
||||
this.stateHashes = getStateHashes(blockstates);
|
||||
this.stackHashes = getStackHashes(blockstates);
|
||||
}
|
||||
|
||||
public BlockOptionalMeta(@Nonnull String selector) {
|
||||
Matcher matcher = pattern.matcher(selector);
|
||||
Matcher matcher = PATTERN.matcher(selector);
|
||||
|
||||
if (!matcher.find()) {
|
||||
throw new IllegalArgumentException("invalid block selector");
|
||||
}
|
||||
|
||||
MatchResult matchResult = matcher.toMatchResult();
|
||||
block = BlockUtils.stringToBlockRequired(matcher.group("id"));
|
||||
|
||||
block = BlockUtils.stringToBlockRequired(matchResult.group(1));
|
||||
blockstates = getStates(block);
|
||||
String props = matcher.group("properties");
|
||||
Map<Property<?>, ?> properties = props == null || props.equals("") ? Collections.emptyMap() : parseProperties(block, props);
|
||||
|
||||
propertiesDescription = props == null ? "{}" : "{" + props.replace("=", ":") + "}";
|
||||
blockstates = getStates(block, properties);
|
||||
stateHashes = getStateHashes(blockstates);
|
||||
stackHashes = getStackHashes(blockstates);
|
||||
}
|
||||
|
||||
private static Set<BlockState> getStates(@Nonnull Block block) {
|
||||
return new HashSet<>(block.getStateDefinition().getPossibleStates());
|
||||
private static <C extends Comparable<C>, P extends Property<C>> P castToIProperty(Object value) {
|
||||
//noinspection unchecked
|
||||
return (P) value;
|
||||
}
|
||||
|
||||
private static Map<Property<?>, ?> parseProperties(Block block, String raw) {
|
||||
ImmutableMap.Builder<Property<?>, Object> builder = ImmutableMap.builder();
|
||||
for (String pair : raw.split(",")) {
|
||||
String[] parts = pair.split("=");
|
||||
if (parts.length != 2) {
|
||||
throw new IllegalArgumentException(String.format("\"%s\" is not a valid property-value pair", pair));
|
||||
}
|
||||
String rawKey = parts[0];
|
||||
String rawValue = parts[1];
|
||||
Property<?> key = block.getStateDefinition().getProperty(rawKey);
|
||||
Comparable<?> value = castToIProperty(key).getValue(rawValue)
|
||||
.orElseThrow(() -> new IllegalArgumentException(String.format(
|
||||
"\"%s\" is not a valid value for %s on %s",
|
||||
rawValue, key, block
|
||||
)));
|
||||
builder.put(key, value);
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private static Set<BlockState> getStates(@Nonnull Block block, @Nonnull Map<Property<?>, ?> properties) {
|
||||
return block.getStateDefinition().getPossibleStates().stream()
|
||||
.filter(blockstate -> properties.entrySet().stream().allMatch(entry ->
|
||||
blockstate.getValue(entry.getKey()) == entry.getValue()
|
||||
))
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
private static ImmutableSet<Integer> getStateHashes(Set<BlockState> blockstates) {
|
||||
@ -145,7 +183,7 @@ public final class BlockOptionalMeta {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("BlockOptionalMeta{block=%s}", block);
|
||||
return String.format("BlockOptionalMeta{block=%s,properties=%s}", block, propertiesDescription);
|
||||
}
|
||||
|
||||
public BlockState getAnyBlockState() {
|
||||
@ -156,6 +194,14 @@ public final class BlockOptionalMeta {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Set<BlockState> getAllBlockStates() {
|
||||
return blockstates;
|
||||
}
|
||||
|
||||
public Set<Integer> stackHashes() {
|
||||
return stackHashes;
|
||||
}
|
||||
|
||||
private static Method getVanillaServerPack;
|
||||
|
||||
private static VanillaPackResources getVanillaServerPack() {
|
||||
@ -199,16 +245,16 @@ public final class BlockOptionalMeta {
|
||||
try {
|
||||
|
||||
getManager().getLootTable(lootTableLocation).getRandomItemsRaw(
|
||||
new LootContext.Builder(
|
||||
new LootParams.Builder(ServerLevelStub.fastCreate())
|
||||
.withParameter(LootContextParams.ORIGIN, Vec3.atLowerCornerOf(BlockPos.ZERO))
|
||||
.withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
|
||||
.withOptionalParameter(LootContextParams.BLOCK_ENTITY, null)
|
||||
.withParameter(LootContextParams.BLOCK_STATE, block.defaultBlockState())
|
||||
.create(LootContextParamSets.BLOCK)
|
||||
new LootContext.Builder(
|
||||
new LootParams.Builder(ServerLevelStub.fastCreate())
|
||||
.withParameter(LootContextParams.ORIGIN, Vec3.atLowerCornerOf(BlockPos.ZERO))
|
||||
.withParameter(LootContextParams.TOOL, ItemStack.EMPTY)
|
||||
.withOptionalParameter(LootContextParams.BLOCK_ENTITY, null)
|
||||
.withParameter(LootContextParams.BLOCK_STATE, block.defaultBlockState())
|
||||
.create(LootContextParamSets.BLOCK)
|
||||
).withOptionalRandomSeed(1L)
|
||||
.create(null),
|
||||
stack -> items.add(stack.getItem())
|
||||
.create(null),
|
||||
stack -> items.add(stack.getItem())
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
|
@ -17,67 +17,70 @@
|
||||
|
||||
package baritone.api.utils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import baritone.api.utils.accessor.IItemStack;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
public class BlockOptionalMetaLookup {
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class BlockOptionalMetaLookup {
|
||||
private final ImmutableSet<Block> blockSet;
|
||||
private final ImmutableSet<BlockState> blockStateSet;
|
||||
private final ImmutableSet<Integer> stackHashes;
|
||||
private final BlockOptionalMeta[] boms;
|
||||
|
||||
public BlockOptionalMetaLookup(BlockOptionalMeta... boms) {
|
||||
this.boms = boms;
|
||||
Set<Block> blocks = new HashSet<>();
|
||||
Set<BlockState> blockStates = new HashSet<>();
|
||||
Set<Integer> stacks = new HashSet<>();
|
||||
for (BlockOptionalMeta bom : boms) {
|
||||
blocks.add(bom.getBlock());
|
||||
blockStates.addAll(bom.getAllBlockStates());
|
||||
stacks.addAll(bom.stackHashes());
|
||||
}
|
||||
this.blockSet = ImmutableSet.copyOf(blocks);
|
||||
this.blockStateSet = ImmutableSet.copyOf(blockStates);
|
||||
this.stackHashes = ImmutableSet.copyOf(stacks);
|
||||
}
|
||||
|
||||
public BlockOptionalMetaLookup(Block... blocks) {
|
||||
this.boms = Stream.of(blocks)
|
||||
this(Stream.of(blocks)
|
||||
.map(BlockOptionalMeta::new)
|
||||
.toArray(BlockOptionalMeta[]::new);
|
||||
.toArray(BlockOptionalMeta[]::new));
|
||||
|
||||
}
|
||||
|
||||
public BlockOptionalMetaLookup(List<Block> blocks) {
|
||||
this.boms = blocks.stream()
|
||||
this(blocks.stream()
|
||||
.map(BlockOptionalMeta::new)
|
||||
.toArray(BlockOptionalMeta[]::new);
|
||||
.toArray(BlockOptionalMeta[]::new));
|
||||
}
|
||||
|
||||
public BlockOptionalMetaLookup(String... blocks) {
|
||||
this.boms = Stream.of(blocks)
|
||||
this(Stream.of(blocks)
|
||||
.map(BlockOptionalMeta::new)
|
||||
.toArray(BlockOptionalMeta[]::new);
|
||||
.toArray(BlockOptionalMeta[]::new));
|
||||
}
|
||||
|
||||
public boolean has(Block block) {
|
||||
for (BlockOptionalMeta bom : boms) {
|
||||
if (bom.getBlock() == block) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return blockSet.contains(block);
|
||||
}
|
||||
|
||||
public boolean has(BlockState state) {
|
||||
for (BlockOptionalMeta bom : boms) {
|
||||
if (bom.matches(state)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return blockStateSet.contains(state);
|
||||
}
|
||||
|
||||
public boolean has(ItemStack stack) {
|
||||
for (BlockOptionalMeta bom : boms) {
|
||||
if (bom.matches(stack)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
int hash = ((IItemStack) (Object) stack).getBaritoneHash();
|
||||
hash -= stack.getDamageValue();
|
||||
return stackHashes.contains(hash);
|
||||
}
|
||||
|
||||
public List<BlockOptionalMeta> blocks() {
|
||||
|
27
src/api/java/baritone/api/utils/BooleanBinaryOperator.java
Normal file
27
src/api/java/baritone/api/utils/BooleanBinaryOperator.java
Normal file
@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
@FunctionalInterface
|
||||
public interface BooleanBinaryOperator {
|
||||
|
||||
boolean applyAsBoolean(boolean a, boolean b);
|
||||
}
|
38
src/api/java/baritone/api/utils/BooleanBinaryOperators.java
Normal file
38
src/api/java/baritone/api/utils/BooleanBinaryOperators.java
Normal file
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public enum BooleanBinaryOperators implements BooleanBinaryOperator {
|
||||
OR((a, b) -> a || b),
|
||||
AND((a, b) -> a && b),
|
||||
XOR((a, b) -> a ^ b);
|
||||
|
||||
private final BooleanBinaryOperator op;
|
||||
|
||||
BooleanBinaryOperators(BooleanBinaryOperator op) {
|
||||
this.op = op;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyAsBoolean(boolean a, boolean b) {
|
||||
return this.op.applyAsBoolean(a, b);
|
||||
}
|
||||
}
|
@ -18,13 +18,13 @@
|
||||
package baritone.api.utils;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.utils.gui.BaritoneToast;
|
||||
import baritone.api.Settings;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.GuiMessageTag;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.stream.Stream;
|
||||
@ -44,10 +44,17 @@ public interface Helper {
|
||||
Helper HELPER = new Helper() {};
|
||||
|
||||
/**
|
||||
* Instance of the game
|
||||
* The main game instance returned by {@link Minecraft#getInstance()}.
|
||||
* Deprecated since {@link IPlayerContext#minecraft()} should be used instead (In the majority of cases).
|
||||
*/
|
||||
@Deprecated
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
/**
|
||||
* The tag to assign to chat messages when {@link Settings#useMessageTag} is {@code true}.
|
||||
*/
|
||||
GuiMessageTag MESSAGE_TAG = new GuiMessageTag(0xFF55FF, null, Component.literal("Baritone message."), "Baritone");
|
||||
|
||||
static Component getPrefix() {
|
||||
// Inner text component
|
||||
final Calendar now = Calendar.getInstance();
|
||||
@ -72,7 +79,7 @@ public interface Helper {
|
||||
* @param message The message to display in the popup
|
||||
*/
|
||||
default void logToast(Component title, Component message) {
|
||||
mc.execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message));
|
||||
Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +140,7 @@ public interface Helper {
|
||||
* @param error Whether to log as an error
|
||||
*/
|
||||
default void logNotificationDirect(String message, boolean error) {
|
||||
mc.execute(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error));
|
||||
Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,13 +167,15 @@ public interface Helper {
|
||||
*/
|
||||
default void logDirect(boolean logAsToast, Component... components) {
|
||||
MutableComponent component = Component.literal("");
|
||||
component.append(getPrefix());
|
||||
component.append(Component.literal(" "));
|
||||
if (!logAsToast && !BaritoneAPI.getSettings().useMessageTag.value) {
|
||||
component.append(getPrefix());
|
||||
component.append(Component.literal(" "));
|
||||
}
|
||||
Arrays.asList(components).forEach(component::append);
|
||||
if (logAsToast) {
|
||||
logToast(getPrefix(), component);
|
||||
} else {
|
||||
mc.execute(() -> BaritoneAPI.getSettings().logger.value.accept(component));
|
||||
Minecraft.getInstance().execute(() -> BaritoneAPI.getSettings().logger.value.accept(component));
|
||||
}
|
||||
}
|
||||
|
||||
@ -226,4 +235,11 @@ public interface Helper {
|
||||
default void logDirect(String message) {
|
||||
logDirect(message, BaritoneAPI.getSettings().logAsToast.value);
|
||||
}
|
||||
|
||||
default void logUnhandledException(final Throwable exception) {
|
||||
HELPER.logDirect("An unhandled exception occurred. " +
|
||||
"The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
|
||||
ChatFormatting.RED);
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
@ -18,9 +18,7 @@
|
||||
package baritone.api.utils;
|
||||
|
||||
import baritone.api.cache.IWorldData;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@ -31,12 +29,18 @@ import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 11/12/2018
|
||||
*/
|
||||
public interface IPlayerContext {
|
||||
|
||||
Minecraft minecraft();
|
||||
|
||||
LocalPlayer player();
|
||||
|
||||
IPlayerController playerController();
|
||||
@ -85,6 +89,12 @@ public interface IPlayerContext {
|
||||
return new Vec3(player().position().x, player().position().y + player().getEyeHeight(), player().position().z);
|
||||
}
|
||||
|
||||
default Vec3 playerMotion() {
|
||||
return player().getDeltaMovement();
|
||||
}
|
||||
|
||||
BetterBlockPos viewerPos();
|
||||
|
||||
default Rotation playerRotations() {
|
||||
return new Rotation(player().getYRot(), player().getXRot());
|
||||
}
|
||||
|
59
src/api/java/baritone/api/utils/Pair.java
Normal file
59
src/api/java/baritone/api/utils/Pair.java
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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 java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
*/
|
||||
public final class Pair<A, B> {
|
||||
|
||||
private final A a;
|
||||
private final B b;
|
||||
|
||||
public Pair(A a, B b) {
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public A first() {
|
||||
return this.a;
|
||||
}
|
||||
|
||||
public B second() {
|
||||
return this.b;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) {
|
||||
return true;
|
||||
}
|
||||
if (o == null || o.getClass() != Pair.class) {
|
||||
return false;
|
||||
}
|
||||
Pair<?, ?> pair = (Pair<?, ?>) o;
|
||||
return Objects.equals(this.a, pair.a) && Objects.equals(this.b, pair.b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 31 * Objects.hashCode(this.a) + Objects.hashCode(this.b);
|
||||
}
|
||||
}
|
@ -51,7 +51,8 @@ public final class RayTraceUtils {
|
||||
} else {
|
||||
start = entity.getEyePosition(1.0F); // do whatever is correct
|
||||
}
|
||||
Vec3 direction = RotationUtils.calcVector3dFromRotation(rotation);
|
||||
|
||||
Vec3 direction = RotationUtils.calcLookDirectionFromRotation(rotation);
|
||||
Vec3 end = start.add(
|
||||
direction.x * blockReachDistance,
|
||||
direction.y * blockReachDistance,
|
||||
|
@ -26,12 +26,12 @@ public class Rotation {
|
||||
/**
|
||||
* The yaw angle of this Rotation
|
||||
*/
|
||||
private float yaw;
|
||||
private final float yaw;
|
||||
|
||||
/**
|
||||
* The pitch angle of this Rotation
|
||||
*/
|
||||
private float pitch;
|
||||
private final float pitch;
|
||||
|
||||
public Rotation(float yaw, float pitch) {
|
||||
this.yaw = yaw;
|
||||
@ -113,6 +113,10 @@ public class Rotation {
|
||||
);
|
||||
}
|
||||
|
||||
public Rotation withPitch(float pitch) {
|
||||
return new Rotation(this.yaw, pitch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is really close to
|
||||
*
|
||||
|
@ -19,7 +19,6 @@ package baritone.api.utils;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import java.util.Optional;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -33,6 +32,8 @@ import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.Shapes;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 9/25/2018
|
||||
@ -43,11 +44,13 @@ public final class RotationUtils {
|
||||
* Constant that a degree value is multiplied by to get the equivalent radian value
|
||||
*/
|
||||
public static final double DEG_TO_RAD = Math.PI / 180.0;
|
||||
public static final float DEG_TO_RAD_F = (float) DEG_TO_RAD;
|
||||
|
||||
/**
|
||||
* Constant that a radian value is multiplied by to get the equivalent degree value
|
||||
*/
|
||||
public static final double RAD_TO_DEG = 180.0 / Math.PI;
|
||||
public static final float RAD_TO_DEG_F = (float) RAD_TO_DEG;
|
||||
|
||||
/**
|
||||
* Offsets from the root block position to the center of each side.
|
||||
@ -128,26 +131,31 @@ public final class RotationUtils {
|
||||
* @param rotation The input rotation
|
||||
* @return Look vector for the rotation
|
||||
*/
|
||||
public static Vec3 calcVector3dFromRotation(Rotation rotation) {
|
||||
float f = Mth.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
|
||||
float f1 = Mth.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
|
||||
float f2 = -Mth.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
|
||||
float f3 = Mth.sin(-rotation.getPitch() * (float) DEG_TO_RAD);
|
||||
return new Vec3((double) (f1 * f2), (double) f3, (double) (f * f2));
|
||||
public static Vec3 calcLookDirectionFromRotation(Rotation rotation) {
|
||||
float flatZ = Mth.cos((-rotation.getYaw() * DEG_TO_RAD_F) - (float) Math.PI);
|
||||
float flatX = Mth.sin((-rotation.getYaw() * DEG_TO_RAD_F) - (float) Math.PI);
|
||||
float pitchBase = -Mth.cos(-rotation.getPitch() * DEG_TO_RAD_F);
|
||||
float pitchHeight = Mth.sin(-rotation.getPitch() * DEG_TO_RAD_F);
|
||||
return new Vec3(flatX * pitchBase, pitchHeight, flatZ * pitchBase);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Vec3 calcVec3dFromRotation(Rotation rotation) {
|
||||
return calcLookDirectionFromRotation(rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ctx Context for the viewing entity
|
||||
* @param pos The target block position
|
||||
* @return The optional rotation
|
||||
* @see #reachable(LocalPlayer, BlockPos, double)
|
||||
* @see #reachable(IPlayerContext, BlockPos, double)
|
||||
*/
|
||||
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos) {
|
||||
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
|
||||
return reachable(ctx, pos, false);
|
||||
}
|
||||
|
||||
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos, boolean wouldSneak) {
|
||||
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance(), wouldSneak);
|
||||
return reachable(ctx, pos, ctx.playerController().getBlockReachDistance(), wouldSneak);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,18 +165,17 @@ public final class RotationUtils {
|
||||
* side that is reachable. The return type will be {@link Optional#empty()} if the entity is
|
||||
* unable to reach any of the sides of the block.
|
||||
*
|
||||
* @param entity The viewing entity
|
||||
* @param ctx Context for 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(LocalPlayer entity, BlockPos pos, double blockReachDistance) {
|
||||
return reachable(entity, pos, blockReachDistance, false);
|
||||
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos, double blockReachDistance) {
|
||||
return reachable(ctx, pos, blockReachDistance, false);
|
||||
}
|
||||
|
||||
public static Optional<Rotation> reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity);
|
||||
if (baritone.getPlayerContext().isLookingAt(pos)) {
|
||||
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
|
||||
if (BaritoneAPI.getSettings().remainWithExistingLookDirection.value && ctx.isLookingAt(pos)) {
|
||||
/*
|
||||
* why add 0.0001?
|
||||
* to indicate that we actually have a desired pitch
|
||||
@ -179,10 +186,10 @@ public final class RotationUtils {
|
||||
*
|
||||
* or if you're a normal person literally all this does it ensure that we don't nudge the pitch to a normal level
|
||||
*/
|
||||
Rotation hypothetical = new Rotation(entity.getYRot(), entity.getXRot() + 0.0001F);
|
||||
Rotation hypothetical = ctx.playerRotations().add(new Rotation(0, 0.0001F));
|
||||
if (wouldSneak) {
|
||||
// the concern here is: what if we're looking at it now, but as soon as we start sneaking we no longer are
|
||||
HitResult result = RayTraceUtils.rayTraceTowards(entity, hypothetical, blockReachDistance, true);
|
||||
HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), hypothetical, blockReachDistance, true);
|
||||
if (result != null && result.getType() == HitResult.Type.BLOCK && ((BlockHitResult) result).getBlockPos().equals(pos)) {
|
||||
return Optional.of(hypothetical); // yes, if we sneaked we would still be looking at the block
|
||||
}
|
||||
@ -190,14 +197,14 @@ public final class RotationUtils {
|
||||
return Optional.of(hypothetical);
|
||||
}
|
||||
}
|
||||
Optional<Rotation> possibleRotation = reachableCenter(entity, pos, blockReachDistance, wouldSneak);
|
||||
Optional<Rotation> possibleRotation = reachableCenter(ctx, pos, blockReachDistance, wouldSneak);
|
||||
//System.out.println("center: " + possibleRotation);
|
||||
if (possibleRotation.isPresent()) {
|
||||
return possibleRotation;
|
||||
}
|
||||
|
||||
BlockState state = entity.level().getBlockState(pos);
|
||||
VoxelShape shape = state.getShape(entity.level(), pos);
|
||||
BlockState state = ctx.world().getBlockState(pos);
|
||||
VoxelShape shape = state.getShape(ctx.world(), pos);
|
||||
if (shape.isEmpty()) {
|
||||
shape = Shapes.block();
|
||||
}
|
||||
@ -205,7 +212,7 @@ public final class RotationUtils {
|
||||
double xDiff = shape.min(Direction.Axis.X) * sideOffset.x + shape.max(Direction.Axis.X) * (1 - sideOffset.x);
|
||||
double yDiff = shape.min(Direction.Axis.Y) * sideOffset.y + shape.max(Direction.Axis.Y) * (1 - sideOffset.y);
|
||||
double zDiff = shape.min(Direction.Axis.Z) * sideOffset.z + shape.max(Direction.Axis.Z) * (1 - sideOffset.z);
|
||||
possibleRotation = reachableOffset(entity, pos, new Vec3(pos.getX(), pos.getY(), pos.getZ()).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak);
|
||||
possibleRotation = reachableOffset(ctx, pos, new Vec3(pos.getX(), pos.getY(), pos.getZ()).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak);
|
||||
if (possibleRotation.isPresent()) {
|
||||
return possibleRotation;
|
||||
}
|
||||
@ -218,12 +225,55 @@ public final class RotationUtils {
|
||||
* the given offsetted position. The return type will be {@link Optional#empty()} if
|
||||
* the entity is unable to reach the block with the offset applied.
|
||||
*
|
||||
* @param entity The viewing entity
|
||||
* @param ctx Context for 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(IPlayerContext ctx, BlockPos pos, Vec3 offsetPos, double blockReachDistance, boolean wouldSneak) {
|
||||
Vec3 eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(ctx.player()) : ctx.player().getEyePosition(1.0F);
|
||||
Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, ctx.playerRotations());
|
||||
Rotation actualRotation = BaritoneAPI.getProvider().getBaritoneForPlayer(ctx.player()).getLookBehavior().getAimProcessor().peekRotation(rotation);
|
||||
HitResult result = RayTraceUtils.rayTraceTowards(ctx.player(), actualRotation, blockReachDistance, wouldSneak);
|
||||
//System.out.println(result);
|
||||
if (result != null && result.getType() == HitResult.Type.BLOCK) {
|
||||
if (((BlockHitResult) result).getBlockPos().equals(pos)) {
|
||||
return Optional.of(rotation);
|
||||
}
|
||||
if (ctx.world().getBlockState(pos).getBlock() instanceof BaseFireBlock && ((BlockHitResult) result).getBlockPos().equals(pos.below())) {
|
||||
return Optional.of(rotation);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified entity is able to reach the specified block where it is
|
||||
* looking at the direct center of it's hitbox.
|
||||
*
|
||||
* @param ctx Context for 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(IPlayerContext ctx, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
|
||||
return reachableOffset(ctx, pos, VecUtils.calculateBlockCenter(ctx.world(), pos), blockReachDistance, wouldSneak);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Optional<Rotation> reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance) {
|
||||
return reachable(entity, pos, blockReachDistance, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Optional<Rotation> reachable(LocalPlayer entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity);
|
||||
IPlayerContext ctx = baritone.getPlayerContext();
|
||||
return reachable(ctx, pos, blockReachDistance, wouldSneak);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3 offsetPos, double blockReachDistance, boolean wouldSneak) {
|
||||
Vec3 eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getEyePosition(1.0F);
|
||||
Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, new Rotation(entity.getYRot(), entity.getXRot()));
|
||||
@ -240,15 +290,7 @@ public final class RotationUtils {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the specified entity is able to reach the specified block where it is
|
||||
* looking at the direct center of it's hitbox.
|
||||
*
|
||||
* @param entity The viewing entity
|
||||
* @param pos The target block position
|
||||
* @param blockReachDistance The block reach distance of the entity
|
||||
* @return The optional rotation
|
||||
*/
|
||||
@Deprecated
|
||||
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
|
||||
return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.level(), pos), blockReachDistance, wouldSneak);
|
||||
}
|
||||
|
@ -47,12 +47,10 @@ import java.util.regex.Pattern;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
|
||||
public class SettingsUtil {
|
||||
|
||||
private static final Path SETTINGS_PATH = Minecraft.getInstance().gameDirectory.toPath().resolve("baritone").resolve("settings.txt");
|
||||
public static final String SETTINGS_DEFAULT_NAME = "settings.txt";
|
||||
private static final Pattern SETTING_PATTERN = Pattern.compile("^(?<setting>[^ ]+) +(?<value>.+)"); // key and value split by the first space
|
||||
private static final String[] JAVA_ONLY_SETTINGS = {"logger", "notifier", "toaster"};
|
||||
|
||||
|
||||
private static boolean isComment(String line) {
|
||||
@ -71,12 +69,12 @@ public class SettingsUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static void readAndApply(Settings settings) {
|
||||
public static void readAndApply(Settings settings, String settingsName) {
|
||||
try {
|
||||
forEachLine(SETTINGS_PATH, line -> {
|
||||
forEachLine(settingsByName(settingsName), line -> {
|
||||
Matcher matcher = SETTING_PATTERN.matcher(line);
|
||||
if (!matcher.matches()) {
|
||||
System.out.println("Invalid syntax in setting file: " + line);
|
||||
Helper.HELPER.logDirect("Invalid syntax in setting file: " + line);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -85,29 +83,33 @@ public class SettingsUtil {
|
||||
try {
|
||||
parseAndApply(settings, settingName, settingValue);
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Unable to parse line " + line);
|
||||
Helper.HELPER.logDirect("Unable to parse line " + line);
|
||||
ex.printStackTrace();
|
||||
}
|
||||
});
|
||||
} catch (NoSuchFileException ignored) {
|
||||
System.out.println("Baritone settings file not found, resetting.");
|
||||
Helper.HELPER.logDirect("Baritone settings file not found, resetting.");
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
|
||||
Helper.HELPER.logDirect("Exception while reading Baritone settings, some settings may be reset to default values!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public static synchronized void save(Settings settings) {
|
||||
try (BufferedWriter out = Files.newBufferedWriter(SETTINGS_PATH)) {
|
||||
try (BufferedWriter out = Files.newBufferedWriter(settingsByName(SETTINGS_DEFAULT_NAME))) {
|
||||
for (Settings.Setting setting : modifiedSettings(settings)) {
|
||||
out.write(settingToString(setting) + "\n");
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
System.out.println("Exception thrown while saving Baritone settings!");
|
||||
Helper.HELPER.logDirect("Exception thrown while saving Baritone settings!");
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private static Path settingsByName(String name) {
|
||||
return Minecraft.getInstance().gameDirectory.toPath().resolve("baritone").resolve(name);
|
||||
}
|
||||
|
||||
public static List<Settings.Setting> modifiedSettings(Settings settings) {
|
||||
List<Settings.Setting> modified = new ArrayList<>();
|
||||
for (Settings.Setting setting : settings.allSettings) {
|
||||
@ -115,7 +117,7 @@ public class SettingsUtil {
|
||||
System.out.println("NULL SETTING?" + setting.getName());
|
||||
continue;
|
||||
}
|
||||
if (javaOnlySetting(setting)) {
|
||||
if (setting.isJavaOnly()) {
|
||||
continue; // NO
|
||||
}
|
||||
if (setting.value == setting.defaultValue) {
|
||||
@ -169,7 +171,7 @@ public class SettingsUtil {
|
||||
}
|
||||
|
||||
public static String settingToString(Settings.Setting setting) throws IllegalStateException {
|
||||
if (javaOnlySetting(setting)) {
|
||||
if (setting.isJavaOnly()) {
|
||||
return setting.getName();
|
||||
}
|
||||
|
||||
@ -177,18 +179,14 @@ public class SettingsUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* This should always be the same as whether the setting can be parsed from or serialized to a string
|
||||
* Deprecated. Use {@link Settings.Setting#isJavaOnly()} instead.
|
||||
*
|
||||
* @param setting The Setting
|
||||
* @return true if the setting can not be set or read by the user
|
||||
*/
|
||||
@Deprecated
|
||||
public static boolean javaOnlySetting(Settings.Setting setting) {
|
||||
for (String name : JAVA_ONLY_SETTINGS) { // no JAVA_ONLY_SETTINGS.contains(...) because that would be case sensitive
|
||||
if (setting.getName().equalsIgnoreCase(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return setting.isJavaOnly();
|
||||
}
|
||||
|
||||
public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
|
||||
|
@ -20,16 +20,19 @@ package baritone.launch.mixins;
|
||||
import baritone.Baritone;
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.event.events.BlockChangeEvent;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.event.events.ChunkEvent;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.api.utils.Pair;
|
||||
import baritone.cache.CachedChunk;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientPacketListener;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.protocol.game.*;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@ -37,6 +40,9 @@ import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/3/2018
|
||||
@ -68,12 +74,14 @@ public class MixinClientPlayNetHandler {
|
||||
}
|
||||
}*/
|
||||
|
||||
@Shadow @Final private Minecraft minecraft;
|
||||
@Shadow
|
||||
@Final
|
||||
private Minecraft minecraft;
|
||||
|
||||
@Inject(
|
||||
method = "sendChat(Ljava/lang/String;)V",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
method = "sendChat(Ljava/lang/String;)V",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true
|
||||
)
|
||||
private void sendChatMessage(String string, CallbackInfo ci) {
|
||||
ChatEvent event = new ChatEvent(string);
|
||||
@ -168,31 +176,22 @@ public class MixinClientPlayNetHandler {
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void postHandleMultiBlockChange(ClientboundSectionBlocksUpdatePacket packetIn, CallbackInfo ci) {
|
||||
if (!Baritone.settings().repackOnAnyBlockChange.value) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((ClientPacketListener) (Object) this);
|
||||
if (baritone == null) {
|
||||
return;
|
||||
}
|
||||
ChunkPos[] chunkPos = new ChunkPos[1];
|
||||
packetIn.runUpdates((pos, state) -> {
|
||||
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(state.getBlock())) {
|
||||
chunkPos[0] = new ChunkPos(pos);
|
||||
}
|
||||
|
||||
List<Pair<BlockPos, BlockState>> changes = new ArrayList<>();
|
||||
packetIn.runUpdates((mutPos, state) -> {
|
||||
changes.add(new Pair<>(mutPos.immutable(), state));
|
||||
});
|
||||
if (chunkPos[0] == null) {
|
||||
if (changes.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
|
||||
LocalPlayer player = ibaritone.getPlayerContext().player();
|
||||
if (player != null && player.connection == (ClientPacketListener) (Object) this) {
|
||||
ibaritone.getGameEventHandler().onChunkEvent(
|
||||
new ChunkEvent(
|
||||
EventState.POST,
|
||||
ChunkEvent.Type.POPULATE_FULL,
|
||||
chunkPos[0].x,
|
||||
chunkPos[0].z
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent(
|
||||
new ChunkPos(changes.get(0).first()),
|
||||
changes
|
||||
));
|
||||
}
|
||||
|
||||
@Inject(
|
||||
@ -210,4 +209,71 @@ public class MixinClientPlayNetHandler {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
@Inject(
|
||||
method = "handleChunkData",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/world/chunk/Chunk.read(Lnet/minecraft/network/PacketBuffer;IZ)V"
|
||||
)
|
||||
)
|
||||
private void preRead(SPacketChunkData packetIn, CallbackInfo ci) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
|
||||
if (baritone == null) {
|
||||
return;
|
||||
}
|
||||
baritone.getGameEventHandler().onChunkEvent(
|
||||
new ChunkEvent(
|
||||
EventState.PRE,
|
||||
packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL,
|
||||
packetIn.getChunkX(),
|
||||
packetIn.getChunkZ()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "handleChunkData",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void postHandleChunkData(SPacketChunkData packetIn, CallbackInfo ci) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
|
||||
if (baritone == null) {
|
||||
return;
|
||||
}
|
||||
baritone.getGameEventHandler().onChunkEvent(
|
||||
new ChunkEvent(
|
||||
EventState.POST,
|
||||
packetIn.isFullChunk() ? ChunkEvent.Type.POPULATE_FULL : ChunkEvent.Type.POPULATE_PARTIAL,
|
||||
packetIn.getChunkX(),
|
||||
packetIn.getChunkZ()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "handleBlockChange",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void postHandleBlockChange(SPacketBlockChange packetIn, CallbackInfo ci) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForConnection((NetHandlerPlayClient) (Object) this);
|
||||
if (baritone == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ChunkPos pos = new ChunkPos(packetIn.getBlockPosition().getX() >> 4, packetIn.getBlockPosition().getZ() >> 4);
|
||||
final Pair<BlockPos, IBlockState> changed = new Pair<>(packetIn.getBlockPosition(), packetIn.getBlockState());
|
||||
baritone.getGameEventHandler().onBlockChange(new BlockChangeEvent(pos, Collections.singletonList(changed)));
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "handleMultiBlockChange",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void postHandleMultiBlockChange(SPacketMultiBlockChange packetIn, CallbackInfo ci) {
|
||||
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
@ -19,15 +19,15 @@ package baritone.launch.mixins;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.event.events.PlayerUpdateEvent;
|
||||
import baritone.api.event.events.SprintStateEvent;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
import baritone.behavior.LookBehavior;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.player.Abilities;
|
||||
import net.minecraft.world.item.ElytraItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
@ -45,9 +45,8 @@ public class MixinClientPlayerEntity {
|
||||
method = "tick",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/client/player/LocalPlayer.isPassenger()Z",
|
||||
shift = At.Shift.BY,
|
||||
by = -3
|
||||
target = "net/minecraft/client/player/AbstractClientPlayer.tick()V",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private void onPreUpdate(CallbackInfo ci) {
|
||||
@ -57,22 +56,6 @@ public class MixinClientPlayerEntity {
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tick",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/client/player/LocalPlayer.sendPosition()V",
|
||||
shift = At.Shift.BY,
|
||||
by = 2
|
||||
)
|
||||
)
|
||||
private void onPostUpdate(CallbackInfo ci) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this);
|
||||
if (baritone != null) {
|
||||
baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST));
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "aiStep",
|
||||
at = @At(
|
||||
@ -124,4 +107,19 @@ public class MixinClientPlayerEntity {
|
||||
((LookBehavior) baritone.getLookBehavior()).pig();
|
||||
}
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
method = "aiStep",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/world/item/ElytraItem.isFlyEnabled(Lnet/minecraft/world/item/ItemStack;)Z"
|
||||
)
|
||||
)
|
||||
private boolean isFlyEnabled(ItemStack stack) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this);
|
||||
if (baritone != null && baritone.getPathingBehavior().isPathing()) {
|
||||
return false;
|
||||
}
|
||||
return ElytraItem.isFlyEnabled(stack);
|
||||
}
|
||||
}
|
||||
|
@ -19,9 +19,12 @@ package baritone.launch.mixins;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.event.events.TabCompleteEvent;
|
||||
import com.mojang.brigadier.ParseResults;
|
||||
import com.mojang.brigadier.context.StringRange;
|
||||
import com.mojang.brigadier.suggestion.Suggestion;
|
||||
import com.mojang.brigadier.suggestion.Suggestions;
|
||||
import net.minecraft.client.gui.components.CommandSuggestions;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@ -33,8 +36,6 @@ import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.client.gui.components.CommandSuggestions;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@ -51,9 +52,18 @@ public class MixinCommandSuggestionHelper {
|
||||
@Final
|
||||
private List<String> commandUsage;
|
||||
|
||||
@Shadow
|
||||
private ParseResults currentParse;
|
||||
|
||||
@Shadow
|
||||
private CompletableFuture<Suggestions> pendingSuggestions;
|
||||
|
||||
@Shadow
|
||||
private CommandSuggestions.SuggestionsList suggestions;
|
||||
|
||||
@Shadow
|
||||
boolean keepSuggestions;
|
||||
|
||||
@Inject(
|
||||
method = "updateCommandInfo",
|
||||
at = @At("HEAD"),
|
||||
@ -74,27 +84,32 @@ public class MixinCommandSuggestionHelper {
|
||||
if (event.completions != null) {
|
||||
ci.cancel();
|
||||
|
||||
this.currentParse = null; // stop coloring
|
||||
|
||||
if (this.keepSuggestions) { // Supress suggestions update when cycling suggestions.
|
||||
return;
|
||||
}
|
||||
|
||||
this.input.setSuggestion(null); // clear old suggestions
|
||||
this.suggestions = null;
|
||||
// TODO: Support populating the command usage
|
||||
this.commandUsage.clear();
|
||||
|
||||
if (event.completions.length == 0) {
|
||||
this.pendingSuggestions = Suggestions.empty();
|
||||
} else {
|
||||
int offset = this.input.getValue().endsWith(" ")
|
||||
? this.input.getCursorPosition()
|
||||
: this.input.getValue().lastIndexOf(" ") + 1; // If there is no space this is still 0 haha yes
|
||||
StringRange range = StringRange.between(prefix.lastIndexOf(" ") + 1, prefix.length()); // if there is no space this starts at 0
|
||||
|
||||
List<Suggestion> suggestionList = Stream.of(event.completions)
|
||||
.map(s -> new Suggestion(StringRange.between(offset, offset + s.length()), s))
|
||||
.map(s -> new Suggestion(range, s))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
Suggestions suggestions = new Suggestions(
|
||||
StringRange.between(offset, offset + suggestionList.stream().mapToInt(s -> s.getText().length()).max().orElse(0)),
|
||||
suggestionList);
|
||||
Suggestions suggestions = new Suggestions(range, suggestionList);
|
||||
|
||||
this.pendingSuggestions = new CompletableFuture<>();
|
||||
this.pendingSuggestions.complete(suggestions);
|
||||
}
|
||||
((CommandSuggestions) (Object) this).showSuggestions(true); // actually populate the suggestions list from the suggestions future
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@ -33,21 +34,25 @@ public class MixinEntity {
|
||||
@Shadow
|
||||
private float yRot;
|
||||
|
||||
float yawRestore;
|
||||
@Shadow
|
||||
private float xRot;
|
||||
|
||||
@Unique
|
||||
private RotationMoveEvent motionUpdateRotationEvent;
|
||||
|
||||
@Inject(
|
||||
method = "moveRelative",
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void moveRelativeHead(CallbackInfo info) {
|
||||
this.yawRestore = this.yRot;
|
||||
// noinspection ConstantConditions
|
||||
if (!LocalPlayer.class.isInstance(this) || BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this) == null) {
|
||||
return;
|
||||
}
|
||||
RotationMoveEvent motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.yRot);
|
||||
this.motionUpdateRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.yRot, this.xRot);
|
||||
BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this).getGameEventHandler().onPlayerRotationMove(motionUpdateRotationEvent);
|
||||
this.yRot = motionUpdateRotationEvent.getYaw();
|
||||
this.yRot = this.motionUpdateRotationEvent.getYaw();
|
||||
this.xRot = this.motionUpdateRotationEvent.getPitch();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
@ -55,6 +60,10 @@ public class MixinEntity {
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void moveRelativeReturn(CallbackInfo info) {
|
||||
this.yRot = this.yawRestore;
|
||||
if (this.motionUpdateRotationEvent != null) {
|
||||
this.yRot = this.motionUpdateRotationEvent.getOriginal().getYaw();
|
||||
this.xRot = this.motionUpdateRotationEvent.getOriginal().getPitch();
|
||||
this.motionUpdateRotationEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.launch.mixins;
|
||||
|
||||
import baritone.utils.accessor.IFireworkRocketEntity;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.OptionalInt;
|
||||
|
||||
@Mixin(FireworkRocketEntity.class)
|
||||
public abstract class MixinFireworkRocketEntity extends Entity implements IFireworkRocketEntity {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private static EntityDataAccessor<OptionalInt> DATA_ATTACHED_TO_TARGET;
|
||||
|
||||
@Shadow
|
||||
private LivingEntity attachedToEntity;
|
||||
|
||||
@Shadow
|
||||
public abstract boolean isAttachedToEntity();
|
||||
|
||||
private MixinFireworkRocketEntity(Level level) {
|
||||
super(EntityType.FIREWORK_ROCKET, level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LivingEntity getBoostedEntity() {
|
||||
if (this.isAttachedToEntity() && this.attachedToEntity == null) { // isAttachedToEntity checks if the optional is present
|
||||
final Entity entity = this.level().getEntity(this.entityData.get(DATA_ATTACHED_TO_TARGET).getAsInt());
|
||||
if (entity instanceof LivingEntity) {
|
||||
this.attachedToEntity = (LivingEntity) entity;
|
||||
}
|
||||
}
|
||||
return this.attachedToEntity;
|
||||
}
|
||||
}
|
@ -25,13 +25,15 @@ import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import static org.objectweb.asm.Opcodes.GETFIELD;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@ -43,9 +45,13 @@ public abstract class MixinLivingEntity extends Entity {
|
||||
/**
|
||||
* Event called to override the movement direction when jumping
|
||||
*/
|
||||
@Unique
|
||||
private RotationMoveEvent jumpRotationEvent;
|
||||
|
||||
public MixinLivingEntity(EntityType<?> entityTypeIn, Level worldIn) {
|
||||
@Unique
|
||||
private RotationMoveEvent elytraRotationEvent;
|
||||
|
||||
private MixinLivingEntity(EntityType<?> entityTypeIn, Level worldIn) {
|
||||
super(entityTypeIn, worldIn);
|
||||
}
|
||||
|
||||
@ -54,14 +60,10 @@ public abstract class MixinLivingEntity extends Entity {
|
||||
at = @At("HEAD")
|
||||
)
|
||||
private void preMoveRelative(CallbackInfo ci) {
|
||||
// noinspection ConstantConditions
|
||||
if (LocalPlayer.class.isInstance(this)) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this);
|
||||
if (baritone != null) {
|
||||
this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.getYRot());
|
||||
baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent);
|
||||
}
|
||||
}
|
||||
this.getBaritone().ifPresent(baritone -> {
|
||||
this.jumpRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.JUMP, this.getYRot(), this.getXRot());
|
||||
baritone.getGameEventHandler().onPlayerRotationMove(this.jumpRotationEvent);
|
||||
});
|
||||
}
|
||||
|
||||
@Redirect(
|
||||
@ -78,5 +80,45 @@ public abstract class MixinLivingEntity extends Entity {
|
||||
return self.getYRot();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "travel",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/world/entity/LivingEntity.getLookAngle()Lnet/minecraft/world/phys/Vec3;"
|
||||
)
|
||||
)
|
||||
private void onPreElytraMove(Vec3 direction, CallbackInfo ci) {
|
||||
this.getBaritone().ifPresent(baritone -> {
|
||||
this.elytraRotationEvent = new RotationMoveEvent(RotationMoveEvent.Type.MOTION_UPDATE, this.getYRot(), this.getXRot());
|
||||
baritone.getGameEventHandler().onPlayerRotationMove(this.elytraRotationEvent);
|
||||
this.setYRot(this.elytraRotationEvent.getYaw());
|
||||
this.setXRot(this.elytraRotationEvent.getPitch());
|
||||
});
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "travel",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/world/entity/LivingEntity.move(Lnet/minecraft/world/entity/MoverType;Lnet/minecraft/world/phys/Vec3;)V",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private void onPostElytraMove(Vec3 direction, CallbackInfo ci) {
|
||||
if (this.elytraRotationEvent != null) {
|
||||
this.setYRot(this.elytraRotationEvent.getOriginal().getYaw());
|
||||
this.setXRot(this.elytraRotationEvent.getOriginal().getPitch());
|
||||
this.elytraRotationEvent = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private Optional<IBaritone> getBaritone() {
|
||||
// noinspection ConstantConditions
|
||||
if (LocalPlayer.class.isInstance(this)) {
|
||||
return Optional.ofNullable(BaritoneAPI.getProvider().getBaritoneForPlayer((LocalPlayer) (Object) this));
|
||||
} else {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package baritone.launch.mixins;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.event.events.PlayerUpdateEvent;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.event.events.WorldEvent;
|
||||
import baritone.api.event.events.type.EventState;
|
||||
@ -29,6 +30,7 @@ import net.minecraft.client.player.LocalPlayer;
|
||||
import org.objectweb.asm.Opcodes;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
@ -49,6 +51,9 @@ public class MixinMinecraft {
|
||||
@Shadow
|
||||
public ClientLevel level;
|
||||
|
||||
@Unique
|
||||
private BiFunction<EventState, TickEvent.Type, TickEvent> tickProvider;
|
||||
|
||||
@Inject(
|
||||
method = "<init>",
|
||||
at = @At("RETURN")
|
||||
@ -57,30 +62,68 @@ public class MixinMinecraft {
|
||||
BaritoneAPI.getProvider().getPrimaryBaritone();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tick",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "net/minecraft/client/Minecraft.screen:Lnet/minecraft/client/gui/screens/Screen;",
|
||||
ordinal = 0,
|
||||
shift = At.Shift.BEFORE
|
||||
),
|
||||
slice = @Slice(
|
||||
from = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.PUTFIELD,
|
||||
target = "net/minecraft/client/Minecraft.missTime:I"
|
||||
)
|
||||
)
|
||||
)
|
||||
private void runTick(CallbackInfo ci) {
|
||||
this.tickProvider = TickEvent.createNextProvider();
|
||||
|
||||
for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) {
|
||||
TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null
|
||||
? TickEvent.Type.IN
|
||||
: TickEvent.Type.OUT;
|
||||
baritone.getGameEventHandler().onTick(this.tickProvider.apply(EventState.PRE, type));
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tick",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void postRunTick(CallbackInfo ci) {
|
||||
if (this.tickProvider == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) {
|
||||
TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null
|
||||
? TickEvent.Type.IN
|
||||
: TickEvent.Type.OUT;
|
||||
baritone.getGameEventHandler().onPostTick(this.tickProvider.apply(EventState.POST, type));
|
||||
}
|
||||
|
||||
this.tickProvider = null;
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tick",
|
||||
at = @At(
|
||||
value = "FIELD",
|
||||
opcode = Opcodes.GETFIELD,
|
||||
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
|
||||
ordinal = 4,
|
||||
shift = At.Shift.BY,
|
||||
by = -3
|
||||
value = "INVOKE",
|
||||
target = "net/minecraft/client/multiplayer/ClientLevel.tickEntities()V",
|
||||
shift = At.Shift.AFTER
|
||||
)
|
||||
)
|
||||
private void runTick(CallbackInfo ci) {
|
||||
final BiFunction<EventState, TickEvent.Type, TickEvent> tickProvider = TickEvent.createNextProvider();
|
||||
|
||||
for (IBaritone baritone : BaritoneAPI.getProvider().getAllBaritones()) {
|
||||
|
||||
TickEvent.Type type = baritone.getPlayerContext().player() != null && baritone.getPlayerContext().world() != null
|
||||
? TickEvent.Type.IN
|
||||
: TickEvent.Type.OUT;
|
||||
|
||||
baritone.getGameEventHandler().onTick(tickProvider.apply(EventState.PRE, type));
|
||||
private void postUpdateEntities(CallbackInfo ci) {
|
||||
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(this.player);
|
||||
if (baritone != null) {
|
||||
// Intentionally call this after all entities have been updated. That way, any modification to rotations
|
||||
// can be recognized by other entity code. (Fireworks and Pigs, for example)
|
||||
baritone.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Inject(
|
||||
|
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.launch.mixins;
|
||||
|
||||
import baritone.utils.accessor.IPalettedContainer.IData;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(targets = "net/minecraft/world/level/chunk/PalettedContainer$Data")
|
||||
public abstract class MixinPalettedContainer$Data<T> implements IData<T> {
|
||||
|
||||
@Accessor
|
||||
public abstract Palette<T> getPalette();
|
||||
|
||||
@Accessor
|
||||
public abstract BitStorage getStorage();
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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.launch.mixins;
|
||||
|
||||
import baritone.utils.accessor.IPalettedContainer;
|
||||
import baritone.utils.accessor.IPalettedContainer.IData;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.world.level.chunk.Palette;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.invoke.MethodType;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
@Mixin(PalettedContainer.class)
|
||||
public abstract class MixinPalettedContainer<T> implements IPalettedContainer<T> {
|
||||
|
||||
private static final MethodHandle DATA_GETTER;
|
||||
|
||||
// Mixin has no way of referring to the data field and we can't use inheritance
|
||||
// tricks to determine its name, so we use this ugly workaround instead.
|
||||
// Classloading is hell here and causes accessor mixins (@Mixin interfaces with
|
||||
// only @Accessor and @Invoker methods) to break on use and proguard hates method
|
||||
// handles and on top of that mojang decided that error messages during world
|
||||
// load are not needed so if you want to debug this you'll probably need an extra
|
||||
// mixin just to display the error and hard quit the game before follow up errors
|
||||
// blow up your log file.
|
||||
// Mumphrey, please add the shadow classes you promised 5 years ago.
|
||||
static {
|
||||
Field dataField = null;
|
||||
for (Field field : PalettedContainer.class.getDeclaredFields()) {
|
||||
Class<?> fieldType = field.getType();
|
||||
if (IData.class.isAssignableFrom(fieldType)) {
|
||||
if ((field.getModifiers() & (Modifier.STATIC | Modifier.FINAL)) != 0 || field.isSynthetic()) {
|
||||
continue;
|
||||
}
|
||||
if (dataField != null) {
|
||||
throw new IllegalStateException("PalettedContainer has more than one Data field.");
|
||||
}
|
||||
dataField = field;
|
||||
}
|
||||
}
|
||||
if (dataField == null) {
|
||||
throw new IllegalStateException("PalettedContainer has no Data field.");
|
||||
}
|
||||
MethodHandle rawGetter;
|
||||
try {
|
||||
rawGetter = MethodHandles.lookup().unreflectGetter(dataField);
|
||||
} catch (IllegalAccessException impossible) {
|
||||
// we literally are the owning class, wtf?
|
||||
throw new IllegalStateException("PalettedContainer may not access its own field?!", impossible);
|
||||
}
|
||||
MethodType getterType = MethodType.methodType(IData.class, PalettedContainer.class);
|
||||
DATA_GETTER = MethodHandles.explicitCastArguments(rawGetter, getterType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Palette<T> getPalette() {
|
||||
return data().getPalette();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BitStorage getStorage() {
|
||||
return data().getStorage();
|
||||
}
|
||||
|
||||
@Unique
|
||||
private IData<T> data() {
|
||||
try {
|
||||
// cast to Object first so the method handle doesn't hide the interface usage from proguard
|
||||
return (IData<T>) (Object) DATA_GETTER.invoke((PalettedContainer<T>) (Object) this);
|
||||
} catch (Throwable t) {
|
||||
throw sneaky(t, RuntimeException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Unique
|
||||
private static <T extends Throwable> T sneaky(Throwable t, Class<T> as) throws T {
|
||||
throw (T) t;
|
||||
}
|
||||
}
|
@ -15,13 +15,16 @@
|
||||
"MixinCommandSuggestionHelper",
|
||||
"MixinEntity",
|
||||
"MixinEntityRenderManager",
|
||||
"MixinFireworkRocketEntity",
|
||||
"MixinItemStack",
|
||||
"MixinLivingEntity",
|
||||
"MixinLootContext",
|
||||
"MixinMinecraft",
|
||||
"MixinNetworkManager",
|
||||
"MixinPalettedContainer",
|
||||
"MixinPalettedContainer$Data",
|
||||
"MixinPlayerController",
|
||||
"MixinScreen",
|
||||
"MixinWorldRenderer"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -20,8 +20,10 @@ package baritone;
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.behavior.IBehavior;
|
||||
import baritone.api.event.listener.IEventBus;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.process.IBaritoneProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.behavior.*;
|
||||
import baritone.cache.WorldProvider;
|
||||
@ -33,16 +35,19 @@ import baritone.utils.BlockStateInterface;
|
||||
import baritone.utils.GuiClick;
|
||||
import baritone.utils.InputOverrideHandler;
|
||||
import baritone.utils.PathingControlManager;
|
||||
import baritone.utils.player.PrimaryPlayerContext;
|
||||
import baritone.utils.player.BaritonePlayerContext;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.SynchronousQueue;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@ -50,87 +55,103 @@ import java.util.concurrent.TimeUnit;
|
||||
*/
|
||||
public class Baritone implements IBaritone {
|
||||
|
||||
private static ThreadPoolExecutor threadPool;
|
||||
private static File dir;
|
||||
private static final ThreadPoolExecutor threadPool;
|
||||
|
||||
static {
|
||||
threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
|
||||
|
||||
dir = new File(Minecraft.getInstance().gameDirectory, "baritone");
|
||||
if (!Files.exists(dir.toPath())) {
|
||||
try {
|
||||
Files.createDirectories(dir.toPath());
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
|
||||
private GameEventHandler gameEventHandler;
|
||||
private final Minecraft mc;
|
||||
private final Path directory;
|
||||
|
||||
private PathingBehavior pathingBehavior;
|
||||
private LookBehavior lookBehavior;
|
||||
private InventoryBehavior inventoryBehavior;
|
||||
private WaypointBehavior waypointBehavior;
|
||||
private InputOverrideHandler inputOverrideHandler;
|
||||
private final GameEventHandler gameEventHandler;
|
||||
|
||||
private FollowProcess followProcess;
|
||||
private MineProcess mineProcess;
|
||||
private GetToBlockProcess getToBlockProcess;
|
||||
private CustomGoalProcess customGoalProcess;
|
||||
private BuilderProcess builderProcess;
|
||||
private ExploreProcess exploreProcess;
|
||||
private BackfillProcess backfillProcess;
|
||||
private FarmProcess farmProcess;
|
||||
private final PathingBehavior pathingBehavior;
|
||||
private final LookBehavior lookBehavior;
|
||||
private final InventoryBehavior inventoryBehavior;
|
||||
private final InputOverrideHandler inputOverrideHandler;
|
||||
|
||||
private PathingControlManager pathingControlManager;
|
||||
private SelectionManager selectionManager;
|
||||
private CommandManager commandManager;
|
||||
private final FollowProcess followProcess;
|
||||
private final MineProcess mineProcess;
|
||||
private final GetToBlockProcess getToBlockProcess;
|
||||
private final CustomGoalProcess customGoalProcess;
|
||||
private final BuilderProcess builderProcess;
|
||||
private final ExploreProcess exploreProcess;
|
||||
private final FarmProcess farmProcess;
|
||||
private final InventoryPauserProcess inventoryPauserProcess;
|
||||
private final ElytraProcess elytraProcess;
|
||||
|
||||
private IPlayerContext playerContext;
|
||||
private WorldProvider worldProvider;
|
||||
private final PathingControlManager pathingControlManager;
|
||||
private final SelectionManager selectionManager;
|
||||
private final CommandManager commandManager;
|
||||
|
||||
private final IPlayerContext playerContext;
|
||||
private final WorldProvider worldProvider;
|
||||
|
||||
public BlockStateInterface bsi;
|
||||
|
||||
Baritone() {
|
||||
Baritone(Minecraft mc) {
|
||||
this.mc = mc;
|
||||
this.gameEventHandler = new GameEventHandler(this);
|
||||
|
||||
this.directory = mc.gameDirectory.toPath().resolve("baritone");
|
||||
if (!Files.exists(this.directory)) {
|
||||
try {
|
||||
Files.createDirectories(this.directory);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
// Define this before behaviors try and get it, or else it will be null and the builds will fail!
|
||||
this.playerContext = PrimaryPlayerContext.INSTANCE;
|
||||
this.playerContext = new BaritonePlayerContext(this, mc);
|
||||
|
||||
{
|
||||
// the Behavior constructor calls baritone.registerBehavior(this) so this populates the behaviors arraylist
|
||||
pathingBehavior = new PathingBehavior(this);
|
||||
lookBehavior = new LookBehavior(this);
|
||||
inventoryBehavior = new InventoryBehavior(this);
|
||||
inputOverrideHandler = new InputOverrideHandler(this);
|
||||
waypointBehavior = new WaypointBehavior(this);
|
||||
this.lookBehavior = this.registerBehavior(LookBehavior::new);
|
||||
this.pathingBehavior = this.registerBehavior(PathingBehavior::new);
|
||||
this.inventoryBehavior = this.registerBehavior(InventoryBehavior::new);
|
||||
this.inputOverrideHandler = this.registerBehavior(InputOverrideHandler::new);
|
||||
this.registerBehavior(WaypointBehavior::new);
|
||||
}
|
||||
|
||||
this.pathingControlManager = new PathingControlManager(this);
|
||||
{
|
||||
this.pathingControlManager.registerProcess(followProcess = new FollowProcess(this));
|
||||
this.pathingControlManager.registerProcess(mineProcess = new MineProcess(this));
|
||||
this.pathingControlManager.registerProcess(customGoalProcess = new CustomGoalProcess(this)); // very high iq
|
||||
this.pathingControlManager.registerProcess(getToBlockProcess = new GetToBlockProcess(this));
|
||||
this.pathingControlManager.registerProcess(builderProcess = new BuilderProcess(this));
|
||||
this.pathingControlManager.registerProcess(exploreProcess = new ExploreProcess(this));
|
||||
this.pathingControlManager.registerProcess(backfillProcess = new BackfillProcess(this));
|
||||
this.pathingControlManager.registerProcess(farmProcess = new FarmProcess(this));
|
||||
this.followProcess = this.registerProcess(FollowProcess::new);
|
||||
this.mineProcess = this.registerProcess(MineProcess::new);
|
||||
this.customGoalProcess = this.registerProcess(CustomGoalProcess::new); // very high iq
|
||||
this.getToBlockProcess = this.registerProcess(GetToBlockProcess::new);
|
||||
this.builderProcess = this.registerProcess(BuilderProcess::new);
|
||||
this.exploreProcess = this.registerProcess(ExploreProcess::new);
|
||||
this.farmProcess = this.registerProcess(FarmProcess::new);
|
||||
this.inventoryPauserProcess = this.registerProcess(InventoryPauserProcess::new);
|
||||
this.elytraProcess = this.registerProcess(ElytraProcess::create);
|
||||
this.registerProcess(BackfillProcess::new);
|
||||
}
|
||||
|
||||
this.worldProvider = new WorldProvider();
|
||||
this.worldProvider = new WorldProvider(this);
|
||||
this.selectionManager = new SelectionManager(this);
|
||||
this.commandManager = new CommandManager(this);
|
||||
}
|
||||
|
||||
public void registerBehavior(IBehavior behavior) {
|
||||
this.gameEventHandler.registerEventListener(behavior);
|
||||
}
|
||||
|
||||
public <T extends IBehavior> T registerBehavior(Function<Baritone, T> constructor) {
|
||||
final T behavior = constructor.apply(this);
|
||||
this.registerBehavior(behavior);
|
||||
return behavior;
|
||||
}
|
||||
|
||||
public <T extends IBaritoneProcess> T registerProcess(Function<Baritone, T> constructor) {
|
||||
final T behavior = constructor.apply(this);
|
||||
this.pathingControlManager.registerProcess(behavior);
|
||||
return behavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingControlManager getPathingControlManager() {
|
||||
return this.pathingControlManager;
|
||||
}
|
||||
|
||||
public void registerBehavior(Behavior behavior) {
|
||||
this.gameEventHandler.registerEventListener(behavior);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputOverrideHandler getInputOverrideHandler() {
|
||||
return this.inputOverrideHandler;
|
||||
@ -170,6 +191,7 @@ public class Baritone implements IBaritone {
|
||||
return this.lookBehavior;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExploreProcess getExploreProcess() {
|
||||
return this.exploreProcess;
|
||||
}
|
||||
@ -179,10 +201,15 @@ public class Baritone implements IBaritone {
|
||||
return this.mineProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FarmProcess getFarmProcess() {
|
||||
return this.farmProcess;
|
||||
}
|
||||
|
||||
public InventoryPauserProcess getInventoryPauserProcess() {
|
||||
return this.inventoryPauserProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathingBehavior getPathingBehavior() {
|
||||
return this.pathingBehavior;
|
||||
@ -208,24 +235,29 @@ public class Baritone implements IBaritone {
|
||||
return this.commandManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IElytraProcess getElytraProcess() {
|
||||
return this.elytraProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openClick() {
|
||||
new Thread(() -> {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
Helper.mc.execute(() -> Helper.mc.setScreen(new GuiClick()));
|
||||
mc.execute(() -> mc.setScreen(new GuiClick()));
|
||||
} catch (Exception ignored) {}
|
||||
}).start();
|
||||
}
|
||||
|
||||
public Path getDirectory() {
|
||||
return this.directory;
|
||||
}
|
||||
|
||||
public static Settings settings() {
|
||||
return BaritoneAPI.getSettings();
|
||||
}
|
||||
|
||||
public static File getDir() {
|
||||
return dir;
|
||||
}
|
||||
|
||||
public static Executor getExecutor() {
|
||||
return threadPool;
|
||||
}
|
||||
|
@ -22,13 +22,15 @@ import baritone.api.IBaritoneProvider;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.command.ICommandSystem;
|
||||
import baritone.api.schematic.ISchematicSystem;
|
||||
import baritone.cache.WorldScanner;
|
||||
import baritone.cache.FasterWorldScanner;
|
||||
import baritone.command.CommandSystem;
|
||||
import baritone.command.ExampleBaritoneControl;
|
||||
import baritone.utils.schematic.SchematicSystem;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@ -36,30 +38,45 @@ import java.util.List;
|
||||
*/
|
||||
public final class BaritoneProvider implements IBaritoneProvider {
|
||||
|
||||
private final Baritone primary;
|
||||
private final List<IBaritone> all;
|
||||
private final List<IBaritone> allView;
|
||||
|
||||
{
|
||||
this.primary = new Baritone();
|
||||
this.all = Collections.singletonList(this.primary);
|
||||
public BaritoneProvider() {
|
||||
this.all = new CopyOnWriteArrayList<>();
|
||||
this.allView = Collections.unmodifiableList(this.all);
|
||||
|
||||
// Setup chat control, just for the primary instance
|
||||
new ExampleBaritoneControl(this.primary);
|
||||
final Baritone primary = (Baritone) this.createBaritone(Minecraft.getInstance());
|
||||
primary.registerBehavior(ExampleBaritoneControl::new);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaritone getPrimaryBaritone() {
|
||||
return primary;
|
||||
return this.all.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaritone> getAllBaritones() {
|
||||
return all;
|
||||
return this.allView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized IBaritone createBaritone(Minecraft minecraft) {
|
||||
IBaritone baritone = this.getBaritoneForMinecraft(minecraft);
|
||||
if (baritone == null) {
|
||||
this.all.add(baritone = new Baritone(minecraft));
|
||||
}
|
||||
return baritone;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean destroyBaritone(IBaritone baritone) {
|
||||
return baritone != this.getPrimaryBaritone() && this.all.remove(baritone);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IWorldScanner getWorldScanner() {
|
||||
return WorldScanner.INSTANCE;
|
||||
return FasterWorldScanner.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -35,6 +35,5 @@ public class Behavior implements IBehavior {
|
||||
protected Behavior(Baritone baritone) {
|
||||
this.baritone = baritone;
|
||||
this.ctx = baritone.getPlayerContext();
|
||||
baritone.registerBehavior(this);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,7 @@ package baritone.behavior;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.event.events.TickEvent;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.utils.ToolSet;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.core.Direction;
|
||||
@ -42,7 +43,10 @@ import java.util.OptionalInt;
|
||||
import java.util.Random;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public final class InventoryBehavior extends Behavior {
|
||||
public final class InventoryBehavior extends Behavior implements Helper {
|
||||
|
||||
int ticksSinceLastInventoryMove;
|
||||
int[] lastTickRequestedMove; // not everything asks every tick, so remember the request while coming to a halt
|
||||
|
||||
public InventoryBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
@ -60,20 +64,28 @@ public final class InventoryBehavior extends Behavior {
|
||||
// we have a crafting table or a chest or something open
|
||||
return;
|
||||
}
|
||||
ticksSinceLastInventoryMove++;
|
||||
if (firstValidThrowaway() >= 9) { // aka there are none on the hotbar, but there are some in main inventory
|
||||
swapWithHotBar(firstValidThrowaway(), 8);
|
||||
requestSwapWithHotBar(firstValidThrowaway(), 8);
|
||||
}
|
||||
int pick = bestToolAgainst(Blocks.STONE, PickaxeItem.class);
|
||||
if (pick >= 9) {
|
||||
swapWithHotBar(pick, 0);
|
||||
requestSwapWithHotBar(pick, 0);
|
||||
}
|
||||
if (lastTickRequestedMove != null) {
|
||||
logDebug("Remembering to move " + lastTickRequestedMove[0] + " " + lastTickRequestedMove[1] + " from a previous tick");
|
||||
requestSwapWithHotBar(lastTickRequestedMove[0], lastTickRequestedMove[1]);
|
||||
}
|
||||
}
|
||||
|
||||
public void attemptToPutOnHotbar(int inMainInvy, Predicate<Integer> disallowedHotbar) {
|
||||
public boolean attemptToPutOnHotbar(int inMainInvy, Predicate<Integer> disallowedHotbar) {
|
||||
OptionalInt destination = getTempHotbarSlot(disallowedHotbar);
|
||||
if (destination.isPresent()) {
|
||||
swapWithHotBar(inMainInvy, destination.getAsInt());
|
||||
if (!requestSwapWithHotBar(inMainInvy, destination.getAsInt())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public OptionalInt getTempHotbarSlot(Predicate<Integer> disallowedHotbar) {
|
||||
@ -97,8 +109,20 @@ public final class InventoryBehavior extends Behavior {
|
||||
return OptionalInt.of(candidates.get(new Random().nextInt(candidates.size())));
|
||||
}
|
||||
|
||||
private void swapWithHotBar(int inInventory, int inHotbar) {
|
||||
private boolean requestSwapWithHotBar(int inInventory, int inHotbar) {
|
||||
lastTickRequestedMove = new int[]{inInventory, inHotbar};
|
||||
if (ticksSinceLastInventoryMove < Baritone.settings().ticksBetweenInventoryMoves.value) {
|
||||
logDebug("Inventory move requested but delaying " + ticksSinceLastInventoryMove + " " + Baritone.settings().ticksBetweenInventoryMoves.value);
|
||||
return false;
|
||||
}
|
||||
if (Baritone.settings().inventoryMoveOnlyIfStationary.value && !baritone.getInventoryPauserProcess().stationaryForInventoryMove()) {
|
||||
logDebug("Inventory move requested but delaying until stationary");
|
||||
return false;
|
||||
}
|
||||
ctx.playerController().windowClick(ctx.player().inventoryMenu.containerId, inInventory < 9 ? inInventory + 36 : inInventory, inHotbar, ClickType.SWAP, ctx.player());
|
||||
ticksSinceLastInventoryMove = 0;
|
||||
lastTickRequestedMove = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
private int firstValidThrowaway() { // TODO offhand idk
|
||||
@ -200,8 +224,8 @@ public final class InventoryBehavior extends Behavior {
|
||||
if (allowInventory) {
|
||||
for (int i = 9; i < 36; i++) {
|
||||
if (desired.test(inv.get(i))) {
|
||||
swapWithHotBar(i, 7);
|
||||
if (select) {
|
||||
requestSwapWithHotBar(i, 7);
|
||||
p.getInventory().selected = 7;
|
||||
}
|
||||
return true;
|
||||
|
@ -20,80 +20,113 @@ package baritone.behavior;
|
||||
import baritone.Baritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.behavior.ILookBehavior;
|
||||
import baritone.api.event.events.PlayerUpdateEvent;
|
||||
import baritone.api.event.events.RotationMoveEvent;
|
||||
import baritone.api.behavior.look.IAimProcessor;
|
||||
import baritone.api.behavior.look.ITickableAimProcessor;
|
||||
import baritone.api.event.events.*;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.api.utils.Rotation;
|
||||
import baritone.behavior.look.ForkableRandom;
|
||||
import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.Optional;
|
||||
|
||||
public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
|
||||
/**
|
||||
* Target's values are as follows:
|
||||
* The current look target, may be {@code null}.
|
||||
*/
|
||||
private Rotation target;
|
||||
private Target target;
|
||||
|
||||
/**
|
||||
* Whether or not rotations are currently being forced
|
||||
* The rotation known to the server. Returned by {@link #getEffectiveRotation()} for use in {@link IPlayerContext}.
|
||||
*/
|
||||
private boolean force;
|
||||
private Rotation serverRotation;
|
||||
|
||||
/**
|
||||
* The last player yaw angle. Used when free looking
|
||||
* The last player rotation. Used to restore the player's angle when using free look.
|
||||
*
|
||||
* @see Settings#freeLook
|
||||
*/
|
||||
private float lastYaw;
|
||||
private Rotation prevRotation;
|
||||
|
||||
private final AimProcessor processor;
|
||||
|
||||
private final Deque<Float> smoothYawBuffer;
|
||||
private final Deque<Float> smoothPitchBuffer;
|
||||
|
||||
public LookBehavior(Baritone baritone) {
|
||||
super(baritone);
|
||||
this.processor = new AimProcessor(baritone.getPlayerContext());
|
||||
this.smoothYawBuffer = new ArrayDeque<>();
|
||||
this.smoothPitchBuffer = new ArrayDeque<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateTarget(Rotation target, boolean force) {
|
||||
this.target = target;
|
||||
if (!force) {
|
||||
double rand = Math.random() - 0.5;
|
||||
if (Math.abs(rand) < 0.1) {
|
||||
rand *= 4;
|
||||
}
|
||||
this.target = new Rotation(this.target.getYaw() + (float) (rand * Baritone.settings().randomLooking113.value), this.target.getPitch());
|
||||
public void updateTarget(Rotation rotation, boolean blockInteract) {
|
||||
this.target = new Target(rotation, Target.Mode.resolve(ctx, blockInteract));
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAimProcessor getAimProcessor() {
|
||||
return this.processor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTick(TickEvent event) {
|
||||
if (event.getType() == TickEvent.Type.IN) {
|
||||
this.processor.tick();
|
||||
}
|
||||
this.force = force || !Baritone.settings().freeLook.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerUpdate(PlayerUpdateEvent event) {
|
||||
System.out.println(event.getState() + " " + ctx.player().getXRot() + " " + ctx.player().getYRot() + " " + ctx.player().xRotO + " " + ctx.player().yRotO);
|
||||
|
||||
if (this.target == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Whether or not we're going to silently set our angles
|
||||
boolean silent = Baritone.settings().antiCheatCompatibility.value && !this.force;
|
||||
|
||||
switch (event.getState()) {
|
||||
case PRE: {
|
||||
if (this.force) {
|
||||
ctx.player().setYRot(this.target.getYaw());
|
||||
float oldPitch = ctx.player().getXRot();
|
||||
float desiredPitch = this.target.getPitch();
|
||||
ctx.player().setXRot(desiredPitch);
|
||||
ctx.player().setYRot((float) (ctx.player().getYRot() + (Math.random() - 0.5) * Baritone.settings().randomLooking.value));
|
||||
ctx.player().setXRot((float) (ctx.player().getXRot() + (Math.random() - 0.5) * Baritone.settings().randomLooking.value));
|
||||
if (desiredPitch == oldPitch && !Baritone.settings().freeLook.value) {
|
||||
nudgeToLevel();
|
||||
}
|
||||
this.target = null;
|
||||
}
|
||||
if (silent) {
|
||||
this.lastYaw = ctx.player().getYRot();
|
||||
ctx.player().setYRot(this.target.getYaw());
|
||||
if (this.target.mode == Target.Mode.NONE) {
|
||||
// Just return for PRE, we still want to set target to null on POST
|
||||
return;
|
||||
}
|
||||
|
||||
this.prevRotation = new Rotation(ctx.player().getYRot(), ctx.player().getXRot());
|
||||
final Rotation actual = this.processor.peekRotation(this.target.rotation);
|
||||
ctx.player().setYRot(actual.getYaw());
|
||||
ctx.player().setXRot(actual.getPitch());
|
||||
break;
|
||||
}
|
||||
case POST: {
|
||||
if (silent) {
|
||||
ctx.player().setYRot(this.lastYaw);
|
||||
this.target = null;
|
||||
// Reset the player's rotations back to their original values
|
||||
if (this.prevRotation != null) {
|
||||
this.smoothYawBuffer.addLast(this.target.rotation.getYaw());
|
||||
while (this.smoothYawBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothYawBuffer.removeFirst();
|
||||
}
|
||||
this.smoothPitchBuffer.addLast(this.target.rotation.getPitch());
|
||||
while (this.smoothPitchBuffer.size() > Baritone.settings().smoothLookTicks.value) {
|
||||
this.smoothPitchBuffer.removeFirst();
|
||||
}
|
||||
if (this.target.mode == Target.Mode.SERVER) {
|
||||
ctx.player().setYRot(this.prevRotation.getYaw());
|
||||
ctx.player().setXRot(this.prevRotation.getPitch());
|
||||
} else if (ctx.player().isFallFlying() ? Baritone.settings().elytraSmoothLook.value : Baritone.settings().smoothLook.value) {
|
||||
ctx.player().setYRot((float) this.smoothYawBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getYaw()));
|
||||
if (ctx.player().isFallFlying()) {
|
||||
ctx.player().setXRot((float) this.smoothPitchBuffer.stream().mapToDouble(d -> d).average().orElse(this.prevRotation.getPitch()));
|
||||
}
|
||||
}
|
||||
//ctx.player().xRotO = prevRotation.getPitch();
|
||||
//ctx.player().yRotO = prevRotation.getYaw();
|
||||
this.prevRotation = null;
|
||||
}
|
||||
// The target is done being used for this game tick, so it can be invalidated
|
||||
this.target = null;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
@ -101,34 +134,227 @@ public final class LookBehavior extends Behavior implements ILookBehavior {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSendPacket(PacketEvent event) {
|
||||
if (!(event.getPacket() instanceof ServerboundMovePlayerPacket)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ServerboundMovePlayerPacket packet = (ServerboundMovePlayerPacket) event.getPacket();
|
||||
if (packet instanceof ServerboundMovePlayerPacket.Rot || packet instanceof ServerboundMovePlayerPacket.PosRot) {
|
||||
this.serverRotation = new Rotation(packet.getYRot(0.0f), packet.getXRot(0.0f));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWorldEvent(WorldEvent event) {
|
||||
this.serverRotation = null;
|
||||
this.target = null;
|
||||
}
|
||||
|
||||
public void pig() {
|
||||
if (this.target != null) {
|
||||
ctx.player().setYRot(this.target.getYaw());
|
||||
final Rotation actual = this.processor.peekRotation(this.target.rotation);
|
||||
ctx.player().setYRot(actual.getYaw());
|
||||
}
|
||||
}
|
||||
|
||||
public Optional<Rotation> getEffectiveRotation() {
|
||||
if (Baritone.settings().freeLook.value) {
|
||||
return Optional.ofNullable(this.serverRotation);
|
||||
}
|
||||
// If freeLook isn't on, just defer to the player's actual rotations
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPlayerRotationMove(RotationMoveEvent event) {
|
||||
if (this.target != null) {
|
||||
final Rotation actual = this.processor.peekRotation(this.target.rotation);
|
||||
event.setYaw(actual.getYaw());
|
||||
event.setPitch(actual.getPitch());
|
||||
}
|
||||
}
|
||||
|
||||
event.setYaw(this.target.getYaw());
|
||||
private static final class AimProcessor extends AbstractAimProcessor {
|
||||
|
||||
// If we have antiCheatCompatibility on, we're going to use the target value later in onPlayerUpdate()
|
||||
// Also the type has to be MOTION_UPDATE because that is called after JUMP
|
||||
if (!Baritone.settings().antiCheatCompatibility.value && event.getType() == RotationMoveEvent.Type.MOTION_UPDATE && !this.force) {
|
||||
this.target = null;
|
||||
public AimProcessor(final IPlayerContext ctx) {
|
||||
super(ctx);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rotation getPrevRotation() {
|
||||
// Implementation will use LookBehavior.serverRotation
|
||||
return ctx.playerRotations();
|
||||
}
|
||||
}
|
||||
|
||||
private static abstract class AbstractAimProcessor implements ITickableAimProcessor {
|
||||
|
||||
protected final IPlayerContext ctx;
|
||||
private final ForkableRandom rand;
|
||||
private double randomYawOffset;
|
||||
private double randomPitchOffset;
|
||||
|
||||
public AbstractAimProcessor(IPlayerContext ctx) {
|
||||
this.ctx = ctx;
|
||||
this.rand = new ForkableRandom();
|
||||
}
|
||||
|
||||
private AbstractAimProcessor(final AbstractAimProcessor source) {
|
||||
this.ctx = source.ctx;
|
||||
this.rand = source.rand.fork();
|
||||
this.randomYawOffset = source.randomYawOffset;
|
||||
this.randomPitchOffset = source.randomPitchOffset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Rotation peekRotation(final Rotation rotation) {
|
||||
final Rotation prev = this.getPrevRotation();
|
||||
|
||||
float desiredYaw = rotation.getYaw();
|
||||
float desiredPitch = rotation.getPitch();
|
||||
|
||||
// In other words, the target doesn't care about the pitch, so it used playerRotations().getPitch()
|
||||
// and it's safe to adjust it to a normal level
|
||||
if (desiredPitch == prev.getPitch()) {
|
||||
desiredPitch = nudgeToLevel(desiredPitch);
|
||||
}
|
||||
|
||||
desiredYaw += this.randomYawOffset;
|
||||
desiredPitch += this.randomPitchOffset;
|
||||
|
||||
return new Rotation(
|
||||
this.calculateMouseMove(prev.getYaw(), desiredYaw),
|
||||
this.calculateMouseMove(prev.getPitch(), desiredPitch)
|
||||
).clamp();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void tick() {
|
||||
// randomLooking
|
||||
this.randomYawOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value;
|
||||
this.randomPitchOffset = (this.rand.nextDouble() - 0.5) * Baritone.settings().randomLooking.value;
|
||||
|
||||
// randomLooking113
|
||||
double random = this.rand.nextDouble() - 0.5;
|
||||
if (Math.abs(random) < 0.1) {
|
||||
random *= 4;
|
||||
}
|
||||
this.randomYawOffset += random * Baritone.settings().randomLooking113.value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void advance(int ticks) {
|
||||
for (int i = 0; i < ticks; i++) {
|
||||
this.tick();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Rotation nextRotation(final Rotation rotation) {
|
||||
final Rotation actual = this.peekRotation(rotation);
|
||||
this.tick();
|
||||
return actual;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ITickableAimProcessor fork() {
|
||||
return new AbstractAimProcessor(this) {
|
||||
|
||||
private Rotation prev = AbstractAimProcessor.this.getPrevRotation();
|
||||
|
||||
@Override
|
||||
public Rotation nextRotation(final Rotation rotation) {
|
||||
return (this.prev = super.nextRotation(rotation));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Rotation getPrevRotation() {
|
||||
return this.prev;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected abstract Rotation getPrevRotation();
|
||||
|
||||
/**
|
||||
* Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1})
|
||||
*/
|
||||
private float nudgeToLevel(float pitch) {
|
||||
if (pitch < -20) {
|
||||
return pitch + 1;
|
||||
} else if (pitch > 10) {
|
||||
return pitch - 1;
|
||||
}
|
||||
return pitch;
|
||||
}
|
||||
|
||||
private float calculateMouseMove(float current, float target) {
|
||||
final float delta = target - current;
|
||||
final double deltaPx = angleToMouse(delta); // yes, even the mouse movements use double
|
||||
return current + mouseToAngle(deltaPx);
|
||||
}
|
||||
|
||||
private double angleToMouse(float angleDelta) {
|
||||
final float minAngleChange = mouseToAngle(1);
|
||||
return Math.round(angleDelta / minAngleChange);
|
||||
}
|
||||
|
||||
private float mouseToAngle(double mouseDelta) {
|
||||
// casting float literals to double gets us the precise values used by mc
|
||||
final double f = ctx.minecraft().options.sensitivity().get() * (double) 0.6f + (double) 0.2f;
|
||||
return (float) (mouseDelta * f * f * f * 8.0d) * 0.15f; // yes, one double and one float scaling factor
|
||||
}
|
||||
}
|
||||
|
||||
private static class Target {
|
||||
|
||||
public final Rotation rotation;
|
||||
public final Mode mode;
|
||||
|
||||
public Target(Rotation rotation, Mode mode) {
|
||||
this.rotation = rotation;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
enum Mode {
|
||||
/**
|
||||
* Rotation will be set client-side and is visual to the player
|
||||
*/
|
||||
CLIENT,
|
||||
|
||||
/**
|
||||
* Rotation will be set server-side and is silent to the player
|
||||
*/
|
||||
SERVER,
|
||||
|
||||
/**
|
||||
* Rotation will remain unaffected on both the client and server
|
||||
*/
|
||||
NONE;
|
||||
|
||||
static Mode resolve(IPlayerContext ctx, boolean blockInteract) {
|
||||
final Settings settings = Baritone.settings();
|
||||
final boolean antiCheat = settings.antiCheatCompatibility.value;
|
||||
final boolean blockFreeLook = settings.blockFreeLook.value;
|
||||
|
||||
if (ctx.player().isFallFlying()) {
|
||||
// always need to set angles while flying
|
||||
return settings.elytraFreeLook.value ? SERVER : CLIENT;
|
||||
} else if (settings.freeLook.value) {
|
||||
// Regardless of if antiCheatCompatibility is enabled, if a blockInteract is requested then the player
|
||||
// rotation needs to be set somehow, otherwise Baritone will halt since objectMouseOver() will just be
|
||||
// whatever the player is mousing over visually. Let's just settle for setting it silently.
|
||||
if (blockInteract) {
|
||||
return blockFreeLook ? SERVER : CLIENT;
|
||||
}
|
||||
return antiCheat ? SERVER : NONE;
|
||||
}
|
||||
|
||||
// all freeLook settings are disabled so set the angles
|
||||
return CLIENT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Nudges the player's pitch to a regular level. (Between {@code -20} and {@code 10}, increments are by {@code 1})
|
||||
*/
|
||||
private void nudgeToLevel() {
|
||||
if (ctx.player().getXRot() < -20) {
|
||||
ctx.player().setXRot(ctx.player().getXRot() + 1);
|
||||
} else if (ctx.player().getXRot() > 10) {
|
||||
ctx.player().setXRot(ctx.player().getXRot() - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,6 +33,7 @@ import baritone.pathing.calc.AbstractNodeCostSearch;
|
||||
import baritone.pathing.movement.CalculationContext;
|
||||
import baritone.pathing.movement.MovementHelper;
|
||||
import baritone.pathing.path.PathExecutor;
|
||||
import baritone.process.ElytraProcess;
|
||||
import baritone.utils.PathRenderer;
|
||||
import baritone.utils.PathingCommandContext;
|
||||
import baritone.utils.pathing.Favoring;
|
||||
@ -238,11 +239,11 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
if (current != null) {
|
||||
switch (event.getState()) {
|
||||
case PRE:
|
||||
lastAutoJump = mc.options.autoJump().get();
|
||||
mc.options.autoJump().set(false);
|
||||
lastAutoJump = ctx.minecraft().options.autoJump().get();
|
||||
ctx.minecraft().options.autoJump().set(false);
|
||||
break;
|
||||
case POST:
|
||||
mc.options.autoJump().set(lastAutoJump);
|
||||
ctx.minecraft().options.autoJump().set(lastAutoJump);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -308,7 +309,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
}
|
||||
|
||||
public boolean isSafeToCancel() {
|
||||
return current == null || safeToCancel;
|
||||
if (current == null) {
|
||||
return !baritone.getElytraProcess().isActive() || baritone.getElytraProcess().isSafeToCancel();
|
||||
}
|
||||
return safeToCancel;
|
||||
}
|
||||
|
||||
public void requestPause() {
|
||||
@ -351,7 +355,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
|
||||
}
|
||||
|
||||
// just cancel the current path
|
||||
private void secretInternalSegmentCancel() {
|
||||
public void secretInternalSegmentCancel() {
|
||||
queuePathEvent(PathEvent.CANCELED);
|
||||
synchronized (pathPlanLock) {
|
||||
getInProgress().ifPresent(AbstractNodeCostSearch::cancel);
|
||||
|
85
src/main/java/baritone/behavior/look/ForkableRandom.java
Normal file
85
src/main/java/baritone/behavior/look/ForkableRandom.java
Normal file
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.look;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.LongSupplier;
|
||||
|
||||
/**
|
||||
* Implementation of Xoroshiro256++
|
||||
* <p>
|
||||
* Extended to produce random double-precision floating point numbers, and allow copies to be spawned via {@link #fork},
|
||||
* which share the same internal state as the source object.
|
||||
*
|
||||
* @author Brady
|
||||
*/
|
||||
public final class ForkableRandom {
|
||||
|
||||
private static final double DOUBLE_UNIT = 0x1.0p-53;
|
||||
|
||||
private final long[] s;
|
||||
|
||||
public ForkableRandom() {
|
||||
this(System.nanoTime() ^ System.currentTimeMillis());
|
||||
}
|
||||
|
||||
public ForkableRandom(long seedIn) {
|
||||
final AtomicLong seed = new AtomicLong(seedIn);
|
||||
final LongSupplier splitmix64 = () -> {
|
||||
long z = seed.addAndGet(0x9e3779b97f4a7c15L);
|
||||
z = (z ^ (z >>> 30)) * 0xbf58476d1ce4e5b9L;
|
||||
z = (z ^ (z >>> 27)) * 0x94d049bb133111ebL;
|
||||
return z ^ (z >>> 31);
|
||||
};
|
||||
this.s = new long[] {
|
||||
splitmix64.getAsLong(),
|
||||
splitmix64.getAsLong(),
|
||||
splitmix64.getAsLong(),
|
||||
splitmix64.getAsLong()
|
||||
};
|
||||
}
|
||||
|
||||
private ForkableRandom(long[] s) {
|
||||
this.s = s;
|
||||
}
|
||||
|
||||
public double nextDouble() {
|
||||
return (this.next() >>> 11) * DOUBLE_UNIT;
|
||||
}
|
||||
|
||||
public long next() {
|
||||
final long result = rotl(this.s[0] + this.s[3], 23) + this.s[0];
|
||||
final long t = this.s[1] << 17;
|
||||
this.s[2] ^= this.s[0];
|
||||
this.s[3] ^= this.s[1];
|
||||
this.s[1] ^= this.s[2];
|
||||
this.s[0] ^= this.s[3];
|
||||
this.s[2] ^= t;
|
||||
this.s[3] = rotl(this.s[3], 45);
|
||||
return result;
|
||||
}
|
||||
|
||||
public ForkableRandom fork() {
|
||||
return new ForkableRandom(Arrays.copyOf(this.s, 4));
|
||||
}
|
||||
|
||||
private static long rotl(long x, int k) {
|
||||
return (x << k) | (x >>> (64 - k));
|
||||
}
|
||||
}
|
11
src/main/java/baritone/cache/CachedChunk.java
vendored
11
src/main/java/baritone/cache/CachedChunk.java
vendored
@ -21,16 +21,17 @@ import baritone.api.utils.BlockUtils;
|
||||
import baritone.utils.pathing.PathingBlockType;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.BitSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/3/2018
|
||||
@ -217,7 +218,7 @@ public final class CachedChunk {
|
||||
// nether roof is always unbreakable
|
||||
return Blocks.BEDROCK.defaultBlockState();
|
||||
}
|
||||
if (y < 5 && dimension.natural()) {
|
||||
if (y < -59 && dimension.natural()) {
|
||||
// solid blocks below 5 are commonly bedrock
|
||||
// however, returning bedrock always would be a little yikes
|
||||
// discourage paths that include breaking blocks below 5 a little more heavily just so that it takes paths breaking what's known to be stone (at 5 or above) instead of what could maybe be bedrock (below 5)
|
||||
|
@ -20,6 +20,10 @@ package baritone.cache;
|
||||
import baritone.Baritone;
|
||||
import baritone.api.cache.ICachedRegion;
|
||||
import baritone.api.utils.BlockUtils;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
@ -27,9 +31,6 @@ import java.nio.file.Paths;
|
||||
import java.util.*;
|
||||
import java.util.zip.GZIPInputStream;
|
||||
import java.util.zip.GZIPOutputStream;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
|
18
src/main/java/baritone/cache/CachedWorld.java
vendored
18
src/main/java/baritone/cache/CachedWorld.java
vendored
@ -23,22 +23,21 @@ import baritone.api.IBaritone;
|
||||
import baritone.api.cache.ICachedWorld;
|
||||
import baritone.api.cache.IWorldData;
|
||||
import baritone.api.utils.Helper;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
@ -71,7 +70,7 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
||||
* All chunk positions pending packing. This map will be updated in-place if a new update to the chunk occurs
|
||||
* while waiting in the queue for the packer thread to get to it.
|
||||
*/
|
||||
private final Map<ChunkPos, LevelChunk> toPackMap = new ConcurrentHashMap<>();
|
||||
private final Map<ChunkPos, LevelChunk> toPackMap = CacheBuilder.newBuilder().softValues().<ChunkPos, LevelChunk>build().asMap();
|
||||
|
||||
private final DimensionType dimension;
|
||||
|
||||
@ -309,6 +308,9 @@ public final class CachedWorld implements ICachedWorld, Helper {
|
||||
try {
|
||||
ChunkPos pos = toPackQueue.take();
|
||||
LevelChunk chunk = toPackMap.remove(pos);
|
||||
if (toPackQueue.size() > Baritone.settings().chunkPackerQueueMaxSize.value) {
|
||||
continue;
|
||||
}
|
||||
CachedChunk cached = ChunkPacker.pack(chunk);
|
||||
CachedWorld.this.updateCachedChunk(cached);
|
||||
//System.out.println("Processed chunk at " + chunk.x + "," + chunk.z);
|
||||
|
@ -34,6 +34,7 @@ import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
import net.minecraft.world.level.dimension.BuiltinDimensionTypes;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static baritone.utils.BlockStateInterface.getFromChunk;
|
||||
|
257
src/main/java/baritone/cache/FasterWorldScanner.java
vendored
Normal file
257
src/main/java/baritone/cache/FasterWorldScanner.java
vendored
Normal file
@ -0,0 +1,257 @@
|
||||
/*
|
||||
* 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.ICachedWorld;
|
||||
import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import baritone.utils.accessor.IPalettedContainer;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.IdMapper;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.util.BitStorage;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public enum FasterWorldScanner implements IWorldScanner {
|
||||
INSTANCE;
|
||||
|
||||
@Override
|
||||
public List<BlockPos> scanChunkRadius(IPlayerContext ctx, BlockOptionalMetaLookup filter, int max, int yLevelThreshold, int maxSearchRadius) {
|
||||
assert ctx.world() != null;
|
||||
if (maxSearchRadius < 0) {
|
||||
throw new IllegalArgumentException("chunkRange must be >= 0");
|
||||
}
|
||||
return scanChunksInternal(ctx, filter, getChunkRange(ctx.playerFeet().x >> 4, ctx.playerFeet().z >> 4, maxSearchRadius), max);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<BlockPos> scanChunk(IPlayerContext ctx, BlockOptionalMetaLookup filter, ChunkPos pos, int max, int yLevelThreshold) {
|
||||
Stream<BlockPos> stream = scanChunkInternal(ctx, filter, pos);
|
||||
if (max >= 0) {
|
||||
stream = stream.limit(max);
|
||||
}
|
||||
return stream.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repack(IPlayerContext ctx) {
|
||||
return this.repack(ctx, 40);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int repack(IPlayerContext ctx, int range) {
|
||||
ChunkSource chunkProvider = ctx.world().getChunkSource();
|
||||
ICachedWorld cachedWorld = ctx.worldData().getCachedWorld();
|
||||
|
||||
BetterBlockPos playerPos = ctx.playerFeet();
|
||||
|
||||
int playerChunkX = playerPos.getX() >> 4;
|
||||
int playerChunkZ = playerPos.getZ() >> 4;
|
||||
|
||||
int minX = playerChunkX - range;
|
||||
int minZ = playerChunkZ - range;
|
||||
int maxX = playerChunkX + range;
|
||||
int maxZ = playerChunkZ + range;
|
||||
|
||||
int queued = 0;
|
||||
for (int x = minX; x <= maxX; x++) {
|
||||
for (int z = minZ; z <= maxZ; z++) {
|
||||
LevelChunk chunk = chunkProvider.getChunk(x, z, false);
|
||||
|
||||
if (chunk != null && !chunk.isEmpty()) {
|
||||
queued++;
|
||||
cachedWorld.queueForPacking(chunk);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return queued;
|
||||
}
|
||||
|
||||
// ordered in a way that the closest blocks are generally first
|
||||
public static List<ChunkPos> getChunkRange(int centerX, int centerZ, int chunkRadius) {
|
||||
List<ChunkPos> chunks = new ArrayList<>();
|
||||
// spiral out
|
||||
chunks.add(new ChunkPos(centerX, centerZ));
|
||||
for (int i = 1; i < chunkRadius; i++) {
|
||||
for (int j = 0; j <= i; j++) {
|
||||
chunks.add(new ChunkPos(centerX - j, centerZ - i));
|
||||
if (j != 0) {
|
||||
chunks.add(new ChunkPos(centerX + j, centerZ - i));
|
||||
chunks.add(new ChunkPos(centerX - j, centerZ + i));
|
||||
}
|
||||
chunks.add(new ChunkPos(centerX + j, centerZ + i));
|
||||
if (j != i) {
|
||||
chunks.add(new ChunkPos(centerX - i, centerZ - j));
|
||||
chunks.add(new ChunkPos(centerX + i, centerZ - j));
|
||||
if (j != 0) {
|
||||
chunks.add(new ChunkPos(centerX - i, centerZ + j));
|
||||
chunks.add(new ChunkPos(centerX + i, centerZ + j));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return chunks;
|
||||
}
|
||||
|
||||
private List<BlockPos> scanChunksInternal(IPlayerContext ctx, BlockOptionalMetaLookup lookup, List<ChunkPos> chunkPositions, int maxBlocks) {
|
||||
assert ctx.world() != null;
|
||||
try {
|
||||
// p -> scanChunkInternal(ctx, lookup, p)
|
||||
Stream<BlockPos> posStream = chunkPositions.parallelStream().flatMap(p -> scanChunkInternal(ctx, lookup, p));
|
||||
if (maxBlocks >= 0) {
|
||||
// WARNING: this can be expensive if maxBlocks is large...
|
||||
// see limit's javadoc
|
||||
posStream = posStream.limit(maxBlocks);
|
||||
}
|
||||
return posStream.collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
private Stream<BlockPos> scanChunkInternal(IPlayerContext ctx, BlockOptionalMetaLookup lookup, ChunkPos pos) {
|
||||
ChunkSource chunkProvider = ctx.world().getChunkSource();
|
||||
// if chunk is not loaded, return empty stream
|
||||
if (!chunkProvider.hasChunk(pos.x, pos.z)) {
|
||||
return Stream.empty();
|
||||
}
|
||||
|
||||
long chunkX = (long) pos.x << 4;
|
||||
long chunkZ = (long) pos.z << 4;
|
||||
|
||||
int playerSectionY = ctx.playerFeet().y >> 4;
|
||||
|
||||
return collectChunkSections(lookup, chunkProvider.getChunk(pos.x, pos.z, false), chunkX, chunkZ, playerSectionY).stream();
|
||||
}
|
||||
|
||||
|
||||
private List<BlockPos> collectChunkSections(BlockOptionalMetaLookup lookup, LevelChunk chunk, long chunkX, long chunkZ, int playerSection) {
|
||||
// iterate over sections relative to player
|
||||
List<BlockPos> blocks = new ArrayList<>();
|
||||
LevelChunkSection[] sections = chunk.getSections();
|
||||
int l = sections.length;
|
||||
int i = playerSection - 1;
|
||||
int j = playerSection;
|
||||
for (; i >= 0 || j < l; ++j, --i) {
|
||||
if (j < l) {
|
||||
visitSection(lookup, sections[j], blocks, chunkX, chunkZ, j);
|
||||
}
|
||||
if (i >= 0) {
|
||||
visitSection(lookup, sections[i], blocks, chunkX, chunkZ, i);
|
||||
}
|
||||
}
|
||||
return blocks;
|
||||
}
|
||||
|
||||
private void visitSection(BlockOptionalMetaLookup lookup, LevelChunkSection section, List<BlockPos> blocks, long chunkX, long chunkZ, int sectionIdx) {
|
||||
if (section == null || section.hasOnlyAir()) {
|
||||
return;
|
||||
}
|
||||
|
||||
PalettedContainer<BlockState> sectionContainer = section.getStates();
|
||||
//this won't work if the PaletteStorage is of the type EmptyPaletteStorage
|
||||
if (((IPalettedContainer<BlockState>) sectionContainer).getStorage() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
boolean[] isInFilter = getIncludedFilterIndices(lookup, ((IPalettedContainer<BlockState>) sectionContainer).getPalette());
|
||||
if (isInFilter.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
BitStorage array = ((IPalettedContainer<BlockState>) section.getStates()).getStorage();
|
||||
long[] longArray = array.getRaw();
|
||||
int arraySize = array.getSize();
|
||||
int bitsPerEntry = array.getBits();
|
||||
long maxEntryValue = (1L << bitsPerEntry) - 1L;
|
||||
|
||||
|
||||
int yOffset = sectionIdx << 4;
|
||||
|
||||
for (int i = 0, idx = 0; i < longArray.length && idx < arraySize; ++i) {
|
||||
long l = longArray[i];
|
||||
for (int offset = 0; offset <= (64 - bitsPerEntry) && idx < arraySize; offset += bitsPerEntry, ++idx) {
|
||||
int value = (int) ((l >> offset) & maxEntryValue);
|
||||
if (isInFilter[value]) {
|
||||
//noinspection DuplicateExpressions
|
||||
blocks.add(new BlockPos(
|
||||
(int) chunkX + ((idx & 255) & 15),
|
||||
yOffset + (idx >> 8),
|
||||
(int) chunkZ + ((idx & 255) >> 4)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private boolean[] getIncludedFilterIndices(BlockOptionalMetaLookup lookup, Palette<BlockState> palette) {
|
||||
boolean commonBlockFound = false;
|
||||
IdMapper<BlockState> paletteMap = getPalette(palette);
|
||||
int size = paletteMap.size();
|
||||
|
||||
boolean[] isInFilter = new boolean[size];
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
BlockState state = paletteMap.byId(i);
|
||||
if (lookup.has(state)) {
|
||||
isInFilter[i] = true;
|
||||
commonBlockFound = true;
|
||||
} else {
|
||||
isInFilter[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!commonBlockFound) {
|
||||
return new boolean[0];
|
||||
}
|
||||
return isInFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* cheats to get the actual map of id -> blockstate from the various palette implementations
|
||||
*/
|
||||
private static IdMapper<BlockState> getPalette(Palette<BlockState> palette) {
|
||||
if (palette instanceof GlobalPalette) {
|
||||
return Block.BLOCK_STATE_REGISTRY;
|
||||
} else {
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
palette.write(buf);
|
||||
int size = buf.readVarInt();
|
||||
IdMapper<BlockState> states = new IdMapper<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
BlockState state = Block.BLOCK_STATE_REGISTRY.byId(buf.readVarInt());
|
||||
assert state != null;
|
||||
states.addMapping(state, i);
|
||||
}
|
||||
return states;
|
||||
}
|
||||
}
|
||||
}
|
185
src/main/java/baritone/cache/WorldProvider.java
vendored
185
src/main/java/baritone/cache/WorldProvider.java
vendored
@ -19,104 +19,84 @@ package baritone.cache;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.cache.IWorldProvider;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.Tuple;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import org.apache.commons.lang3.SystemUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.client.server.IntegratedServer;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* @author Brady
|
||||
* @since 8/4/2018
|
||||
*/
|
||||
public class WorldProvider implements IWorldProvider, Helper {
|
||||
public class WorldProvider implements IWorldProvider {
|
||||
|
||||
private static final Map<Path, WorldData> worldCache = new HashMap<>(); // this is how the bots have the same cached world
|
||||
private static final Map<Path, WorldData> worldCache = new HashMap<>();
|
||||
|
||||
private final Baritone baritone;
|
||||
private final IPlayerContext ctx;
|
||||
private WorldData currentWorld;
|
||||
private Level mcWorld; // this let's us detect a broken load/unload hook
|
||||
|
||||
/**
|
||||
* This lets us detect a broken load/unload hook.
|
||||
* @see #detectAndHandleBrokenLoading()
|
||||
*/
|
||||
private Level mcWorld;
|
||||
|
||||
public WorldProvider(Baritone baritone) {
|
||||
this.baritone = baritone;
|
||||
this.ctx = baritone.getPlayerContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final WorldData getCurrentWorld() {
|
||||
detectAndHandleBrokenLoading();
|
||||
this.detectAndHandleBrokenLoading();
|
||||
return this.currentWorld;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a new world is initialized to discover the
|
||||
*
|
||||
* @param world The world's Registry Data
|
||||
* @param world The new world
|
||||
*/
|
||||
public final void initWorld(ResourceKey<Level> worldKey, DimensionType world) {
|
||||
Path directory;
|
||||
Path readme;
|
||||
public final void initWorld(Level world) {
|
||||
this.getSaveDirectories(world).ifPresent(dirs -> {
|
||||
final Path worldDir = dirs.getA();
|
||||
final Path readmeDir = dirs.getB();
|
||||
|
||||
IntegratedServer integratedServer = mc.getSingleplayerServer();
|
||||
|
||||
// If there is an integrated server running (Aka Singleplayer) then do magic to find the world save file
|
||||
if (mc.hasSingleplayerServer()) {
|
||||
directory = DimensionType.getStorageFolder(worldKey, integratedServer.getWorldPath(LevelResource.ROOT));
|
||||
|
||||
// Gets the "depth" of this directory relative the the game's run directory, 2 is the location of the world
|
||||
if (directory.relativize(mc.gameDirectory.toPath()).getNameCount() != 2) {
|
||||
// subdirectory of the main save directory for this world
|
||||
directory = directory.getParent();
|
||||
}
|
||||
|
||||
directory = directory.resolve("baritone");
|
||||
readme = directory;
|
||||
} else { // Otherwise, the server must be remote...
|
||||
String folderName;
|
||||
if (mc.getCurrentServer() != null) {
|
||||
folderName = mc.isConnectedToRealms() ? "realms" : mc.getCurrentServer().ip;
|
||||
} else {
|
||||
//replaymod causes null currentServer and false singleplayer.
|
||||
System.out.println("World seems to be a replay. Not loading Baritone cache.");
|
||||
currentWorld = null;
|
||||
mcWorld = mc.level;
|
||||
return;
|
||||
}
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
folderName = folderName.replace(":", "_");
|
||||
}
|
||||
directory = Baritone.getDir().toPath().resolve(folderName);
|
||||
readme = Baritone.getDir().toPath();
|
||||
}
|
||||
|
||||
// lol wtf is this baritone folder in my minecraft save?
|
||||
try (FileOutputStream out = new FileOutputStream(readme.resolve("readme.txt").toFile())) {
|
||||
// good thing we have a readme
|
||||
out.write("https://github.com/cabaletta/baritone\n".getBytes());
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
// We will actually store the world data in a subfolder: "DIM<id>"
|
||||
Path dir = getDimDir(worldKey, world.logicalHeight(), directory);
|
||||
if (!Files.exists(dir)) {
|
||||
try {
|
||||
Files.createDirectories(dir);
|
||||
// lol wtf is this baritone folder in my minecraft save?
|
||||
// good thing we have a readme
|
||||
Files.createDirectories(readmeDir);
|
||||
Files.write(
|
||||
readmeDir.resolve("readme.txt"),
|
||||
"https://github.com/cabaletta/baritone\n".getBytes(StandardCharsets.US_ASCII)
|
||||
);
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
|
||||
System.out.println("Baritone world data dir: " + dir);
|
||||
synchronized (worldCache) {
|
||||
this.currentWorld = worldCache.computeIfAbsent(dir, d -> new WorldData(d, world));
|
||||
}
|
||||
this.mcWorld = mc.level;
|
||||
}
|
||||
// We will actually store the world data in a subfolder: "DIM<id>"
|
||||
final Path worldDataDir = this.getWorldDataDirectory(worldDir, world);
|
||||
try {
|
||||
Files.createDirectories(worldDataDir);
|
||||
} catch (IOException ignored) {}
|
||||
|
||||
public final Path getDimDir(ResourceKey<Level> level, int height, Path directory) {
|
||||
return directory.resolve(level.location().getNamespace()).resolve(level.location().getPath() + "_" + height);
|
||||
System.out.println("Baritone world data dir: " + worldDataDir);
|
||||
synchronized (worldCache) {
|
||||
this.currentWorld = worldCache.computeIfAbsent(worldDataDir, d -> new WorldData(d, world.dimensionType()));
|
||||
}
|
||||
this.mcWorld = ctx.world();
|
||||
});
|
||||
}
|
||||
|
||||
public final void closeWorld() {
|
||||
@ -129,26 +109,73 @@ public class WorldProvider implements IWorldProvider, Helper {
|
||||
world.onClose();
|
||||
}
|
||||
|
||||
public final void ifWorldLoaded(Consumer<WorldData> currentWorldConsumer) {
|
||||
detectAndHandleBrokenLoading();
|
||||
if (this.currentWorld != null) {
|
||||
currentWorldConsumer.accept(this.currentWorld);
|
||||
}
|
||||
private Path getWorldDataDirectory(Path parent, Level world) {
|
||||
ResourceLocation dimId = world.dimension().location();
|
||||
int height = world.dimensionType().logicalHeight();
|
||||
return parent.resolve(dimId.getNamespace()).resolve(dimId.getPath() + "_" + height);
|
||||
}
|
||||
|
||||
private final void detectAndHandleBrokenLoading() {
|
||||
if (this.mcWorld != mc.level) {
|
||||
/**
|
||||
* @param world The world
|
||||
* @return An {@link Optional} containing the world's baritone dir and readme dir, or {@link Optional#empty()} if
|
||||
* the world isn't valid for caching.
|
||||
*/
|
||||
private Optional<Tuple<Path, Path>> getSaveDirectories(Level world) {
|
||||
Path worldDir;
|
||||
Path readmeDir;
|
||||
|
||||
// If there is an integrated server running (Aka Singleplayer) then do magic to find the world save file
|
||||
if (ctx.minecraft().hasSingleplayerServer()) {
|
||||
worldDir = ctx.minecraft().getSingleplayerServer().getWorldPath(LevelResource.ROOT);
|
||||
|
||||
// Gets the "depth" of this directory relative to the game's run directory, 2 is the location of the world
|
||||
if (worldDir.relativize(ctx.minecraft().gameDirectory.toPath()).getNameCount() != 2) {
|
||||
// subdirectory of the main save directory for this world
|
||||
worldDir = worldDir.getParent();
|
||||
}
|
||||
|
||||
worldDir = worldDir.resolve("baritone");
|
||||
readmeDir = worldDir;
|
||||
} else { // Otherwise, the server must be remote...
|
||||
String folderName;
|
||||
final ServerData serverData = ctx.minecraft().getCurrentServer();
|
||||
if (serverData != null) {
|
||||
folderName = ctx.minecraft().isConnectedToRealms() ? "realms" : serverData.ip;
|
||||
} else {
|
||||
//replaymod causes null currentServer and false singleplayer.
|
||||
System.out.println("World seems to be a replay. Not loading Baritone cache.");
|
||||
currentWorld = null;
|
||||
mcWorld = ctx.world();
|
||||
return Optional.empty();
|
||||
}
|
||||
if (SystemUtils.IS_OS_WINDOWS) {
|
||||
folderName = folderName.replace(":", "_");
|
||||
}
|
||||
// TODO: This should probably be in "baritone/servers"
|
||||
worldDir = baritone.getDirectory().resolve(folderName);
|
||||
// Just write the readme to the baritone directory instead of each server save in it
|
||||
readmeDir = baritone.getDirectory();
|
||||
}
|
||||
|
||||
return Optional.of(new Tuple<>(worldDir, readmeDir));
|
||||
}
|
||||
|
||||
/**
|
||||
* Why does this exist instead of fixing the event? Some mods break the event. Lol.
|
||||
*/
|
||||
private void detectAndHandleBrokenLoading() {
|
||||
if (this.mcWorld != ctx.world()) {
|
||||
if (this.currentWorld != null) {
|
||||
System.out.println("mc.world unloaded unnoticed! Unloading Baritone cache now.");
|
||||
closeWorld();
|
||||
}
|
||||
if (mc.level != null) {
|
||||
if (ctx.world() != null) {
|
||||
System.out.println("mc.world loaded unnoticed! Loading Baritone cache now.");
|
||||
initWorld(mc.level.dimension(), mc.level.dimensionType());
|
||||
initWorld(ctx.world());
|
||||
}
|
||||
} else if (currentWorld == null && mc.level != null && (mc.hasSingleplayerServer() || mc.getCurrentServer() != null)) {
|
||||
} else if (this.currentWorld == null && ctx.world() != null && (ctx.minecraft().hasSingleplayerServer() || ctx.minecraft().getCurrentServer() != null)) {
|
||||
System.out.println("Retrying to load Baritone cache");
|
||||
initWorld(mc.level.dimension(), mc.level.dimensionType());
|
||||
initWorld(ctx.world());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,8 +22,6 @@ import baritone.api.cache.IWorldScanner;
|
||||
import baritone.api.utils.BetterBlockPos;
|
||||
import baritone.api.utils.BlockOptionalMetaLookup;
|
||||
import baritone.api.utils.IPlayerContext;
|
||||
import java.util.*;
|
||||
import java.util.stream.IntStream;
|
||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
@ -33,6 +31,9 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public enum WorldScanner implements IWorldScanner {
|
||||
|
||||
INSTANCE;
|
||||
|
@ -17,8 +17,8 @@
|
||||
|
||||
package baritone.command;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.Settings;
|
||||
import baritone.api.command.argument.ICommandArgument;
|
||||
import baritone.api.command.exception.CommandNotEnoughArgumentsException;
|
||||
@ -27,9 +27,9 @@ import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import baritone.api.command.manager.ICommandManager;
|
||||
import baritone.api.event.events.ChatEvent;
|
||||
import baritone.api.event.events.TabCompleteEvent;
|
||||
import baritone.api.event.listener.AbstractGameEventListener;
|
||||
import baritone.api.utils.Helper;
|
||||
import baritone.api.utils.SettingsUtil;
|
||||
import baritone.behavior.Behavior;
|
||||
import baritone.command.argument.ArgConsumer;
|
||||
import baritone.command.argument.CommandArguments;
|
||||
import baritone.command.manager.CommandManager;
|
||||
@ -46,14 +46,14 @@ import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
|
||||
|
||||
public class ExampleBaritoneControl implements Helper, AbstractGameEventListener {
|
||||
public class ExampleBaritoneControl extends Behavior implements Helper {
|
||||
|
||||
private static final Settings settings = BaritoneAPI.getSettings();
|
||||
private final ICommandManager manager;
|
||||
|
||||
public ExampleBaritoneControl(IBaritone baritone) {
|
||||
public ExampleBaritoneControl(Baritone baritone) {
|
||||
super(baritone);
|
||||
this.manager = baritone.getCommandManager();
|
||||
baritone.getGameEventHandler().registerEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -97,7 +97,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener
|
||||
return false;
|
||||
} else if (msg.trim().equalsIgnoreCase("orderpizza")) {
|
||||
try {
|
||||
((IGuiScreen) mc.screen).openLinkInvoker(new URI("https://www.dominos.com/en/pages/order/"));
|
||||
((IGuiScreen) ctx.minecraft().screen).openLinkInvoker(new URI("https://www.dominos.com/en/pages/order/"));
|
||||
} catch (NullPointerException | URISyntaxException ignored) {}
|
||||
return false;
|
||||
}
|
||||
@ -121,7 +121,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener
|
||||
}
|
||||
} else if (argc.hasExactlyOne()) {
|
||||
for (Settings.Setting setting : settings.allSettings) {
|
||||
if (SettingsUtil.javaOnlySetting(setting)) {
|
||||
if (setting.isJavaOnly()) {
|
||||
continue;
|
||||
}
|
||||
if (setting.getName().equalsIgnoreCase(pair.getA())) {
|
||||
@ -174,7 +174,7 @@ public class ExampleBaritoneControl implements Helper, AbstractGameEventListener
|
||||
.stream();
|
||||
}
|
||||
Settings.Setting setting = settings.byLowerName.get(argc.getString().toLowerCase(Locale.US));
|
||||
if (setting != null && !SettingsUtil.javaOnlySetting(setting)) {
|
||||
if (setting != null && !setting.isJavaOnly()) {
|
||||
if (setting.getValueClass() == Boolean.class) {
|
||||
TabCompleteHelper helper = new TabCompleteHelper();
|
||||
if ((Boolean) setting.value) {
|
||||
|
@ -380,6 +380,8 @@ public class ArgConsumer implements IArgConsumer {
|
||||
public <T extends IDatatype> Stream<String> tabCompleteDatatype(T datatype) {
|
||||
try {
|
||||
return datatype.tabComplete(this.context);
|
||||
} catch (CommandException ignored) {
|
||||
// NOP
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
@ -35,10 +35,11 @@ import java.util.stream.Stream;
|
||||
|
||||
public class BuildCommand extends Command {
|
||||
|
||||
private static final File schematicsDir = new File(mc.gameDirectory, "schematics");
|
||||
private final File schematicsDir;
|
||||
|
||||
public BuildCommand(IBaritone baritone) {
|
||||
super(baritone, "build");
|
||||
this.schematicsDir = new File(baritone.getPlayerContext().minecraft().gameDirectory, "schematics");
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -21,12 +21,11 @@ import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.exception.CommandInvalidStateException;
|
||||
import baritone.api.pathing.goals.GoalBlock;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
public class ComeCommand extends Command {
|
||||
|
||||
@ -37,11 +36,7 @@ public class ComeCommand extends Command {
|
||||
@Override
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
args.requireMax(0);
|
||||
Entity entity = mc.getCameraEntity();
|
||||
if (entity == null) {
|
||||
throw new CommandInvalidStateException("render view entity is null");
|
||||
}
|
||||
baritone.getCustomGoalProcess().setGoalAndPath(new GoalBlock(entity.blockPosition()));
|
||||
baritone.getCustomGoalProcess().setGoalAndPath(new GoalBlock(ctx.viewerPos()));
|
||||
logDirect("Coming");
|
||||
}
|
||||
|
||||
|
@ -66,7 +66,8 @@ public final class DefaultCommands {
|
||||
new WaypointsCommand(baritone),
|
||||
new CommandAlias(baritone, "sethome", "Sets your home waypoint", "waypoints save home"),
|
||||
new CommandAlias(baritone, "home", "Path to your home waypoint", "waypoints goto home"),
|
||||
new SelCommand(baritone)
|
||||
new SelCommand(baritone),
|
||||
new ElytraCommand(baritone)
|
||||
));
|
||||
ExecutionControlCommands prc = new ExecutionControlCommands(baritone);
|
||||
commands.add(prc.pauseCommand);
|
||||
|
225
src/main/java/baritone/command/defaults/ElytraCommand.java
Normal file
225
src/main/java/baritone/command/defaults/ElytraCommand.java
Normal file
@ -0,0 +1,225 @@
|
||||
/*
|
||||
* 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.command.defaults;
|
||||
|
||||
import baritone.Baritone;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.command.exception.CommandInvalidStateException;
|
||||
import baritone.api.command.helpers.TabCompleteHelper;
|
||||
import baritone.api.pathing.goals.Goal;
|
||||
import baritone.api.process.ICustomGoalProcess;
|
||||
import baritone.api.process.IElytraProcess;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.HoverEvent;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
|
||||
|
||||
public class ElytraCommand extends Command {
|
||||
|
||||
public ElytraCommand(IBaritone baritone) {
|
||||
super(baritone, "elytra");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
final ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess();
|
||||
final IElytraProcess elytra = baritone.getElytraProcess();
|
||||
if (args.hasExactlyOne() && args.peekString().equals("supported")) {
|
||||
logDirect(elytra.isLoaded() ? "yes" : unsupportedSystemMessage());
|
||||
return;
|
||||
}
|
||||
if (!elytra.isLoaded()) {
|
||||
throw new CommandInvalidStateException(unsupportedSystemMessage());
|
||||
}
|
||||
|
||||
if (!args.hasAny()) {
|
||||
if (Baritone.settings().elytraTermsAccepted.value) {
|
||||
if (detectOn2b2t()) {
|
||||
warn2b2t();
|
||||
}
|
||||
} else {
|
||||
gatekeep();
|
||||
}
|
||||
Goal iGoal = customGoalProcess.mostRecentGoal();
|
||||
if (iGoal == null) {
|
||||
throw new CommandInvalidStateException("No goal has been set");
|
||||
}
|
||||
if (ctx.world().dimension() != Level.NETHER) {
|
||||
throw new CommandInvalidStateException("Only works in the nether");
|
||||
}
|
||||
try {
|
||||
elytra.pathTo(iGoal);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
throw new CommandInvalidStateException(ex.getMessage());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
final String action = args.getString();
|
||||
switch (action) {
|
||||
case "reset": {
|
||||
elytra.resetState();
|
||||
logDirect("Reset state but still flying to same goal");
|
||||
break;
|
||||
}
|
||||
case "repack": {
|
||||
elytra.repackChunks();
|
||||
logDirect("Queued all loaded chunks for repacking");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
throw new CommandInvalidStateException("Invalid action");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void warn2b2t() {
|
||||
if (Baritone.settings().elytraPredictTerrain.value) {
|
||||
long seed = Baritone.settings().elytraNetherSeed.value;
|
||||
if (seed != NEW_2B2T_SEED && seed != OLD_2B2T_SEED) {
|
||||
logDirect(Component.literal("It looks like you're on 2b2t, but elytraNetherSeed is incorrect.")); // match color
|
||||
logDirect(suggest2b2tSeeds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Component suggest2b2tSeeds() {
|
||||
MutableComponent clippy = Component.literal("");
|
||||
clippy.append("Within a few hundred blocks of spawn/axis/highways/etc, the terrain is too fragmented to be predictable. Baritone Elytra will still work, just with backtracking. ");
|
||||
clippy.append("However, once you get more than a few thousand blocks out, you should try ");
|
||||
MutableComponent olderSeed = Component.literal("the older seed (click here)");
|
||||
olderSeed.setStyle(olderSeed.getStyle().withUnderlined(true).withBold(true).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(Baritone.settings().prefix.value + "set elytraNetherSeed " + OLD_2B2T_SEED))).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + OLD_2B2T_SEED)));
|
||||
clippy.append(olderSeed);
|
||||
clippy.append(". Once you're further out into newer terrain generation (this includes everything up through 1.12), you should try ");
|
||||
MutableComponent newerSeed = Component.literal("the newer seed (click here)");
|
||||
newerSeed.setStyle(newerSeed.getStyle().withUnderlined(true).withBold(true).withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(Baritone.settings().prefix.value + "set elytraNetherSeed " + NEW_2B2T_SEED))).withClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, FORCE_COMMAND_PREFIX + "set elytraNetherSeed " + NEW_2B2T_SEED)));
|
||||
clippy.append(newerSeed);
|
||||
clippy.append(". Once you get into 1.19 terrain, the terrain becomes unpredictable again, due to custom non-vanilla generation, and you should set #elytraPredictTerrain to false. ");
|
||||
return clippy;
|
||||
}
|
||||
|
||||
private void gatekeep() {
|
||||
MutableComponent gatekeep = Component.literal("");
|
||||
gatekeep.append("To disable this message, enable the setting elytraTermsAccepted\n");
|
||||
gatekeep.append("Baritone Elytra is an experimental feature. It is only intended for long distance travel in the Nether using fireworks for vanilla boost. It will not work with any other mods (\"hacks\") for non-vanilla boost. ");
|
||||
MutableComponent gatekeep2 = Component.literal("If you want Baritone to attempt to take off from the ground for you, you can enable the elytraAutoJump setting (not advisable on laggy servers!). ");
|
||||
gatekeep2.setStyle(gatekeep2.getStyle().withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(Baritone.settings().prefix.value + "set elytraAutoJump true"))));
|
||||
gatekeep.append(gatekeep2);
|
||||
MutableComponent gatekeep3 = Component.literal("If you want Baritone to go slower, enable the elytraConserveFireworks setting and/or decrease the elytraFireworkSpeed setting. ");
|
||||
gatekeep3.setStyle(gatekeep3.getStyle().withHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, Component.literal(Baritone.settings().prefix.value + "set elytraConserveFireworks true\n" + Baritone.settings().prefix.value + "set elytraFireworkSpeed 0.6\n(the 0.6 number is just an example, tweak to your liking)"))));
|
||||
gatekeep.append(gatekeep3);
|
||||
MutableComponent gatekeep4 = Component.literal("Baritone Elytra ");
|
||||
MutableComponent red = Component.literal("wants to know the seed");
|
||||
red.setStyle(red.getStyle().withColor(ChatFormatting.RED).withUnderlined(true).withBold(true));
|
||||
gatekeep4.append(red);
|
||||
gatekeep4.append(" of the world you are in. If it doesn't have the correct seed, it will frequently backtrack. It uses the seed to generate terrain far beyond what you can see, since terrain obstacles in the Nether can be much larger than your render distance. ");
|
||||
gatekeep.append(gatekeep4);
|
||||
gatekeep.append("\n");
|
||||
if (detectOn2b2t()) {
|
||||
MutableComponent gatekeep5 = Component.literal("It looks like you're on 2b2t. ");
|
||||
gatekeep5.append(suggest2b2tSeeds());
|
||||
if (!Baritone.settings().elytraPredictTerrain.value) {
|
||||
gatekeep5.append(Baritone.settings().prefix.value + "elytraPredictTerrain is currently disabled. ");
|
||||
} else {
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
gatekeep5.append("You are using the newer seed. ");
|
||||
} else if (Baritone.settings().elytraNetherSeed.value == OLD_2B2T_SEED) {
|
||||
gatekeep5.append("You are using the older seed. ");
|
||||
} else {
|
||||
gatekeep5.append("Defaulting to the newer seed. ");
|
||||
Baritone.settings().elytraNetherSeed.value = NEW_2B2T_SEED;
|
||||
}
|
||||
}
|
||||
gatekeep.append(gatekeep5);
|
||||
} else {
|
||||
if (Baritone.settings().elytraNetherSeed.value == NEW_2B2T_SEED) {
|
||||
MutableComponent gatekeep5 = Component.literal("Baritone doesn't know the seed of your world. Set it with: " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere\n");
|
||||
gatekeep5.append("For the time being, elytraPredictTerrain is defaulting to false since the seed is unknown.");
|
||||
gatekeep.append(gatekeep5);
|
||||
Baritone.settings().elytraPredictTerrain.value = false;
|
||||
} else {
|
||||
if (Baritone.settings().elytraPredictTerrain.value) {
|
||||
MutableComponent gatekeep5 = Component.literal("Baritone Elytra is predicting terrain assuming that " + Baritone.settings().elytraNetherSeed.value + " is the correct seed. Change that with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, or disable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain false");
|
||||
gatekeep.append(gatekeep5);
|
||||
} else {
|
||||
MutableComponent gatekeep5 = Component.literal("Baritone Elytra is not predicting terrain. If you don't know the seed, this is the correct thing to do. If you do know the seed, input it with " + Baritone.settings().prefix.value + "set elytraNetherSeed seedgoeshere, and then enable it with " + Baritone.settings().prefix.value + "set elytraPredictTerrain true");
|
||||
gatekeep.append(gatekeep5);
|
||||
}
|
||||
}
|
||||
}
|
||||
logDirect(gatekeep);
|
||||
}
|
||||
|
||||
private boolean detectOn2b2t() {
|
||||
ServerData data = ctx.minecraft().getCurrentServer();
|
||||
return data != null && data.ip.toLowerCase().contains("2b2t.org");
|
||||
}
|
||||
|
||||
private static final long OLD_2B2T_SEED = -4100785268875389365L;
|
||||
private static final long NEW_2B2T_SEED = 146008555100680L;
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
TabCompleteHelper helper = new TabCompleteHelper();
|
||||
if (args.hasExactlyOne()) {
|
||||
helper.append("reset", "repack", "supported");
|
||||
}
|
||||
return helper.filterPrefix(args.getString()).stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getShortDesc() {
|
||||
return "elytra time";
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getLongDesc() {
|
||||
return Arrays.asList(
|
||||
"The elytra command tells baritone to, in the nether, automatically fly to the current goal.",
|
||||
"",
|
||||
"Usage:",
|
||||
"> elytra - fly to the current goal",
|
||||
"> elytra reset - Resets the state of the process, but will try to keep flying to the same goal.",
|
||||
"> elytra repack - Queues all of the chunks in render distance to be given to the native library.",
|
||||
"> elytra supported - Tells you if baritone ships a native library that is compatible with your PC."
|
||||
);
|
||||
}
|
||||
|
||||
private static String unsupportedSystemMessage() {
|
||||
final String osArch = System.getProperty("os.arch");
|
||||
final String osName = System.getProperty("os.name");
|
||||
return String.format(
|
||||
"Legacy architectures are not supported. Your CPU is %s and your operating system is %s. " +
|
||||
"Supported architectures are 64 bit x86, and 64 bit ARM. Supported operating systems are Windows, " +
|
||||
"Linux, and Mac",
|
||||
osArch, osName
|
||||
);
|
||||
}
|
||||
}
|
@ -41,7 +41,7 @@ public class ExploreFilterCommand extends Command {
|
||||
@Override
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
args.requireMax(2);
|
||||
File file = args.getDatatypePost(RelativeFile.INSTANCE, mc.gameDirectory.getAbsoluteFile().getParentFile());
|
||||
File file = args.getDatatypePost(RelativeFile.INSTANCE, ctx.minecraft().gameDirectory.getAbsoluteFile().getParentFile());
|
||||
boolean invert = false;
|
||||
if (args.hasAny()) {
|
||||
if (args.getString().equalsIgnoreCase("invert")) {
|
||||
@ -65,7 +65,7 @@ public class ExploreFilterCommand extends Command {
|
||||
@Override
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
if (args.hasExactlyOne()) {
|
||||
return RelativeFile.tabComplete(args, RelativeFile.gameDir());
|
||||
return RelativeFile.tabComplete(args, RelativeFile.gameDir(ctx.minecraft()));
|
||||
}
|
||||
return Stream.empty();
|
||||
}
|
||||
|
@ -51,7 +51,7 @@ public class GoalCommand extends Command {
|
||||
}
|
||||
} else {
|
||||
args.requireMax(3);
|
||||
BetterBlockPos origin = baritone.getPlayerContext().playerFeet();
|
||||
BetterBlockPos origin = ctx.playerFeet();
|
||||
Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin);
|
||||
goalProcess.setGoal(goal);
|
||||
logDirect(String.format("Goal: %s", goal.toString()));
|
||||
|
@ -20,7 +20,6 @@ package baritone.command.defaults;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.datatypes.BlockById;
|
||||
import baritone.api.command.datatypes.ForBlockOptionalMeta;
|
||||
import baritone.api.command.datatypes.RelativeCoordinate;
|
||||
import baritone.api.command.datatypes.RelativeGoal;
|
||||
@ -46,7 +45,7 @@ public class GotoCommand extends Command {
|
||||
// is no need to handle the case of empty arguments.
|
||||
if (args.peekDatatypeOrNull(RelativeCoordinate.INSTANCE) != null) {
|
||||
args.requireMax(3);
|
||||
BetterBlockPos origin = baritone.getPlayerContext().playerFeet();
|
||||
BetterBlockPos origin = ctx.playerFeet();
|
||||
Goal goal = args.getDatatypePost(RelativeGoal.INSTANCE, origin);
|
||||
logDirect(String.format("Going to: %s", goal.toString()));
|
||||
baritone.getCustomGoalProcess().setGoalAndPath(goal);
|
||||
@ -61,7 +60,8 @@ public class GotoCommand extends Command {
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
// since it's either a goal or a block, I don't think we can tab complete properly?
|
||||
// so just tab complete for the block variant
|
||||
return args.tabCompleteDatatype(BlockById.INSTANCE);
|
||||
args.requireMax(1);
|
||||
return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,14 +17,13 @@
|
||||
|
||||
package baritone.command.defaults;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.datatypes.BlockById;
|
||||
import baritone.api.command.datatypes.ForBlockOptionalMeta;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.utils.BlockOptionalMeta;
|
||||
import baritone.cache.WorldScanner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@ -45,14 +44,18 @@ public class MineCommand extends Command {
|
||||
while (args.hasAny()) {
|
||||
boms.add(args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE));
|
||||
}
|
||||
WorldScanner.INSTANCE.repack(ctx);
|
||||
BaritoneAPI.getProvider().getWorldScanner().repack(ctx);
|
||||
logDirect(String.format("Mining %s", boms.toString()));
|
||||
baritone.getMineProcess().mine(quantity, boms.toArray(new BlockOptionalMeta[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) {
|
||||
return args.tabCompleteDatatype(BlockById.INSTANCE);
|
||||
public Stream<String> tabComplete(String label, IArgConsumer args) throws CommandException {
|
||||
args.getAsOrDefault(Integer.class, 0);
|
||||
while (args.has(2)) {
|
||||
args.getDatatypeFor(ForBlockOptionalMeta.INSTANCE);
|
||||
}
|
||||
return args.tabCompleteDatatype(ForBlockOptionalMeta.INSTANCE);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -17,12 +17,12 @@
|
||||
|
||||
package baritone.command.defaults;
|
||||
|
||||
import baritone.api.BaritoneAPI;
|
||||
import baritone.api.IBaritone;
|
||||
import baritone.api.command.Command;
|
||||
import baritone.api.command.argument.IArgConsumer;
|
||||
import baritone.api.command.exception.CommandException;
|
||||
import baritone.api.process.ICustomGoalProcess;
|
||||
import baritone.cache.WorldScanner;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
@ -38,7 +38,7 @@ public class PathCommand extends Command {
|
||||
public void execute(String label, IArgConsumer args) throws CommandException {
|
||||
ICustomGoalProcess customGoalProcess = baritone.getCustomGoalProcess();
|
||||
args.requireMax(0);
|
||||
WorldScanner.INSTANCE.repack(ctx);
|
||||
BaritoneAPI.getProvider().getWorldScanner().repack(ctx);
|
||||
customGoalProcess.path();
|
||||
logDirect("Now pathing");
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user