Compare commits

...

179 Commits

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