Compare commits

...

212 Commits

Author SHA1 Message Date
Leijurv
3cb4700b16 v1.0.0 2018-10-15 17:21:24 -07:00
Leijurv
94921fe03f update simpletweaker version in proguard too 2018-10-15 17:21:02 -07:00
Leijurv
0202865837 Merge branch 'master' of github.com:cabaletta/baritone 2018-10-15 17:01:35 -07:00
Leijurv
b9b911eb3b add impact link 2018-10-15 17:01:29 -07:00
Brady
54fb2c5f81 Update to SimpleTweaker 1.2 2018-10-15 19:00:52 -05:00
Leijurv
2df97ff986 update install link 2018-10-15 16:55:13 -07:00
Leijurv
4374619ba2 update install and impact information 2018-10-15 16:22:03 -07:00
Leijurv
6b6ebd6968 optimize all imports 2018-10-15 16:16:04 -07:00
Leijurv
b41fdc2bbd remove spammy log prints 2018-10-15 15:39:01 -07:00
Leijurv
3cac37d1a5 cached regions in ram should not expand without bound 2018-10-15 15:19:10 -07:00
Brady
2f7259714a Fix Pathing Thread crash on Forge 2018-10-14 23:46:41 -05:00
Leijurv
c1076461e2 dont jump while using an item, fixes #222 2018-10-14 10:38:47 -07:00
Leijurv
6fdf845349 v0.0.9 2018-10-14 10:27:50 -07:00
Brady
c80b855dab Move a lot of utils to api 2018-10-14 00:55:30 -05:00
Brady
83fc11e75b private static final > private final static 2018-10-14 00:24:59 -05:00
Brady
9654892e54 Make BlockStateInterface.AIR final 2018-10-14 00:23:49 -05:00
Brady
b46fad1442 Fix bad reference 2018-10-13 23:27:11 -05:00
Brady
ff652dbe40 scanLoadedChunks -> scanChunkRadius 2018-10-13 23:15:34 -05:00
leijurv
897483884a fix 2 block parkour failure on lilypads and after descends 2018-10-13 17:01:40 -07:00
Leijurv
ba68990ef8 update codacy badge 2018-10-13 12:36:05 -07:00
Leijurv
de29a6532f privatize 2018-10-13 12:29:14 -07:00
Leijurv
9045791e7f cleanup 2018-10-13 12:28:20 -07:00
Leijurv
ab2fa0ba88 update instructions for new build system 2018-10-12 21:36:41 -07:00
Leijurv
56b67cbc47 no longer needed 2018-10-12 21:21:51 -07:00
leijurv
b6a1608e73 some improvements 2018-10-12 21:19:24 -07:00
Brady
6277c20e4c funny number 2018-10-12 22:15:54 -05:00
Brady
2fc282477d No need to override Read 2018-10-12 22:13:21 -05:00
Brady
917f393f7a Merge pull request #221 from cabaletta/gradle-proguard
Proguard Gradle Build Magic
2018-10-12 21:39:47 -05:00
Brady
045504ecf7 No differences. 100% NONE 2018-10-12 21:38:05 -05:00
Leijurv
7efc0ae8ca fix snow bs 2018-10-12 19:33:03 -07:00
Brady
3958dce341 cancer 2018-10-12 21:31:33 -05:00
Brady
d1a9012deb 2 spaces 2018-10-12 21:24:35 -05:00
Leijurv
dbde993a76 Merge branch 'master' into gradle-proguard 2018-10-12 19:24:18 -07:00
Brady
96c66d2809 CreateDist task 2018-10-12 21:21:16 -05:00
Brady
df1633b2a1 You shouldn't write a json to a jar and treat it like a jar 2018-10-12 20:42:24 -05:00
Brady
24f18f0ac2 Json sorting 2018-10-12 19:47:13 -05:00
Brady
416fea2aa5 Remove unnecessary removeIf usage 2018-10-12 18:10:54 -05:00
Brady
93286a646f Use Gradle Internal Pair 2018-10-12 18:08:15 -05:00
Brady
8fba36c05e Initial Proguard Task meme
Working Determinizer, but it doesn't sort the JSON object keys
time to rek travis
2018-10-12 17:56:09 -05:00
Leijurv
b443be1795 more accurate check 2018-10-12 15:29:25 -07:00
Leijurv
4892192c6c remove unused functions 2018-10-12 15:14:39 -07:00
Leijurv
6b7a8e2bd3 better protection logic, fix placing outside worldborder 2018-10-12 14:34:33 -07:00
Leijurv
c5f5445f4b fix exception when calculating descend from starting position above 256 2018-10-12 14:19:11 -07:00
Leijurv
8a65f43a0b check world border, fixes #218 2018-10-12 14:12:06 -07:00
Leijurv
76e4a1a649 brag about reproducible builds some more 2018-10-11 21:22:46 -07:00
Leijurv
5167c0c886 zip too 2018-10-11 21:12:00 -07:00
Leijurv
9d3d8f6c82 forgot install 2018-10-11 21:05:00 -07:00
Leijurv
7e4a1169af extract, sort, and reinsert refmap json into final jar 2018-10-11 21:04:07 -07:00
Leijurv
773ad89951 refactor problematic area 2018-10-11 20:36:18 -07:00
Leijurv
c2adcdb051 fix 2018-10-11 20:11:35 -07:00
Leijurv
b75bc6d03d comment out until its back online 2018-10-11 20:04:45 -07:00
Leijurv
e3b80f11ad brag about how reproducible our builds are 2018-10-11 20:02:26 -07:00
Leijurv
f33a2ef11b fully automated reproducible space deterministic builds 2018-10-11 18:52:58 -07:00
Brady
130b21f738 Fix issue with user input check that messed up Auto Eat 2018-10-11 18:50:55 -05:00
Leijurv
ee954d6a4e break proguard less 2018-10-11 13:24:23 -07:00
Brady
54215bdb18 Just ONE tweaker
When we make the next release, we need to specify in the setup files that Baritone now requires the SimpleTweaker dependency, and we need to remove the old alternate tweaker references. (Optifine and Forge)
2018-10-11 14:53:20 -05:00
Leijurv
0db18a7caf v0.0.8 2018-10-11 11:48:07 -07:00
Leijurv
a1c0f4dbb4 keep baritone provider properly 2018-10-11 11:10:59 -07:00
Brady
db7d3184c9 fINAL 2018-10-11 12:34:40 -05:00
Brady
7dfe6ac3ca Add EntityPlayerSP field to relevant events 2018-10-11 12:32:42 -05:00
Leijurv
8fd921c60e disable cancelOnGoalInvalidation 2018-10-10 21:28:55 -07:00
Leijurv
fec29d03fd automatically break block while suffocating, fixes #33 2018-10-10 21:25:21 -07:00
Leijurv
9bd205f190 center pillar regardless of timing 2018-10-10 21:07:59 -07:00
Leijurv
089037663e tweak backtrack cost favoring coefficient 2018-10-10 21:06:31 -07:00
leijurv
8c0bc3e2ef splice tighter, fixes #44 2018-10-10 20:49:25 -07:00
leijurv
db21045cfb renderPathIgnoreDepth 2018-10-10 20:40:15 -07:00
Leijurv
fbf0f2271c revamp pathStart, fixes #209 2018-10-10 17:05:51 -07:00
Leijurv
7e78ed2139 rework minebehavior threading model, fixes #217 2018-10-10 16:40:33 -07:00
Leijurv
5676acbba6 add off hand, fixes #206 2018-10-10 16:29:48 -07:00
Leijurv
43b155d7b8 better check than air 2018-10-10 16:27:48 -07:00
Brady
93158226b6 The sources jar should use SRG names not MCP 2018-10-10 14:10:02 -05:00
Leijurv
d3bf4ef198 renderSelectionBoxesIgnoreDepth 2018-10-09 19:34:53 -07:00
Leijurv
fc9d13a03c there was literally no reason to have it like that 2018-10-09 17:36:35 -07:00
Leijurv
22d2036657 splice better, fixes #215 2018-10-09 16:40:04 -07:00
Leijurv
9e15960581 fix pause stuttering, fixes #216 2018-10-09 16:13:46 -07:00
leijurv
738ce25ff0 tighten fall column 2018-10-09 11:15:42 -07:00
Brady
5da9347e2c Merge pull request #214 from cabaletta/path-api
Pathing API
2018-10-09 00:14:25 -05:00
Brady
771e892b31 Get Cutoff implementation out of API we DON'T need you 2018-10-09 00:10:50 -05:00
Leijurv
9df5f942de add shebang 2018-10-08 22:01:57 -07:00
Brady
0fb5f3233f MovementStatus javadocs 2018-10-08 23:52:36 -05:00
Leijurv
f17ce87e45 publicize 2018-10-08 21:51:19 -07:00
Leijurv
a497a944a6 bottom of the class 2018-10-08 21:49:36 -07:00
Brady
2e69bbe371 Minimal CutoffResult Javadocs 2018-10-08 23:34:12 -05:00
Brady
875f01c358 More comprehensive IPath javadocs 2018-10-08 23:29:16 -05:00
Leijurv
8e1d827819 v0.0.7 2018-10-08 20:57:06 -07:00
Brady
6a4a8ab2d9 I'm an IDIOT 2018-10-08 21:09:54 -05:00
Brady
8278576227 Rename getCurrentPathSearch to getPathFinder 2018-10-08 21:02:55 -05:00
Brady
7d0aa4d7a5 Add override annotation to getPath in PathExecutor 2018-10-08 20:39:33 -05:00
Brady
2b4512ee3f Move to API 2018-10-08 20:37:52 -05:00
Leijurv
413e505683 epic 2018-10-08 18:08:01 -07:00
Leijurv
0f1edba5f1 save settings 2018-10-08 18:05:08 -07:00
Brady
e23a9c976a Bad code 2018-10-08 20:01:44 -05:00
Brady
1449edb8af Didn't need to do that 2018-10-08 19:59:25 -05:00
Brady
d177db5a35 IMovement
Hey would you look at that
2018-10-08 19:57:22 -05:00
Brady
1245e222a7 Begin path api prep 2018-10-08 19:23:43 -05:00
Leijurv
336154fd9b clean up build and remove unnecessary files 2018-10-08 15:25:09 -07:00
Brady
0ee14b4b90 Good javadocs
They're not good they're shit I lied to you
2018-10-08 17:12:51 -05:00
Leijurv
5a9e5cdac4 move rendering, fixes #212 2018-10-08 15:11:07 -07:00
Brady
10bb177664 Add renderGoalIgnoreDepth setting 2018-10-08 17:06:41 -05:00
leijurv
69762bf4b4 fix parkour maybe? fixes #211 2018-10-07 22:08:37 -07:00
leijurv
e17cc79cb3 synchronize MemoryBehavior, fixes #198 2018-10-07 21:55:40 -07:00
leijurv
60c29fd159 actually stop sprinting, fixes #199 2018-10-07 21:40:18 -07:00
Leijurv
7481c98dbc more documentation 2018-10-07 17:57:07 -07:00
Leijurv
796b45601e add info about reproducibility 2018-10-07 17:39:13 -07:00
Leijurv
b5347cebc3 cleanup build gradle 2018-10-07 17:02:21 -07:00
Leijurv
65ce5ca752 fix nullpointerexception in cachedworld 2018-10-07 16:57:04 -07:00
Leijurv
d1e62ef8f2 ok but really this time they're deterministic 2018-10-07 16:56:46 -07:00
Leijurv
db8daf4c59 maybe in jar 2018-10-07 16:07:35 -07:00
Leijurv
80240cb9f2 maybe needs to be higher 2018-10-07 14:23:29 -07:00
Leijurv
4da0731664 deterministic 2018-10-07 12:00:18 -07:00
leijurv
af357d4d8e fix a weird bug 2018-10-06 20:28:47 -07:00
Leijurv
8c76573395 don't pause on one block overlap 2018-10-06 18:43:20 -07:00
Leijurv
939e9c32d5 pause when current best is a backtrack, fixes #201 2018-10-06 18:39:48 -07:00
Brady
e4ef659756 Fix WorldScanner exposure 2018-10-06 20:35:32 -05:00
Brady
4b61452c62 Expose WorldScanner in API 2018-10-06 20:30:09 -05:00
Brady
d5130aa6ba Expose event listener registry in API 2018-10-06 20:16:38 -05:00
Leijurv
6c9f317f31 don't look to the side on a parkour place until the place is in range 2018-10-05 18:27:02 -07:00
Leijurv
1ab5609d4e spam travis less 2018-10-05 15:51:23 -07:00
Leijurv
78b626af23 v0.0.6 2018-10-05 15:42:02 -07:00
Leijurv
046de84360 that should really default to true 2018-10-05 14:39:17 -07:00
Leijurv
ca48dabcc7 change sneak-backplace behavior, fixes #208 2018-10-05 13:49:47 -07:00
Leijurv
9880a4e948 when asusmeSafeWalk is on, we don't sneak in the first place 2018-10-05 13:11:09 -07:00
Leijurv
cb589219d8 use mutable move result to avoid instantianing ten million move result objects 2018-10-05 12:32:42 -07:00
Leijurv
6fff4c5254 reduce repetition in Moves 2018-10-05 10:17:58 -07:00
Leijurv
4049c116d9 dynamicY and yOffset 2018-10-05 10:10:24 -07:00
Leijurv
b720742f53 render the goal block, fixes #166 2018-10-04 21:28:34 -07:00
leijurv
c1af050fa6 fix lilypad fall cost, fixes #207 2018-10-04 16:01:27 -07:00
Leijurv
39f415d4be allowplace and allowparkourplace 2018-10-03 19:00:58 -07:00
Leijurv
4590b9f6da they say you are what you eat, but i don't remember eating a minecraft damn daniel mod 2018-10-03 13:45:43 -07:00
Brady
ee6e0b1784 Add message and actually cancel event 2018-10-03 12:45:57 -05:00
Brady
820c108548 Add pause "command" in ExampleBaritoneControl 2018-10-03 12:44:28 -05:00
Leijurv
239bb14e3a add blockBreakAdditionalPenalty 2018-10-03 08:20:24 -07:00
Leijurv
1bd7c8455f crucial performance optimization 2018-10-03 08:14:15 -07:00
Leijurv
6986f179cd it's not much of an improvement, but it won't make it slower 2018-10-03 08:12:57 -07:00
Leijurv
28af41b789 defer movement propagation and assembly to postprocessing 2018-10-03 08:04:30 -07:00
Leijurv
36bdaa99ec DAE BlockPos bad? 2018-10-03 07:57:24 -07:00
Leijurv
1ee44024b2 don't construct favored positions hashset if the coefficient renders it useless 2018-10-03 07:52:17 -07:00
Leijurv
cd926283b3 avoid synthetic lambda creation 2018-10-03 07:48:26 -07:00
Leijurv
04d210bd8b no need to calculate the hash on contstruction anymore 2018-10-03 07:43:45 -07:00
Leijurv
38895beb5d remove width and height override part 2: electric boogaloo 2018-10-02 17:15:00 -07:00
Leijurv
3fdc4d6ee0 parkour jumping onto a vine, sort of 2018-10-02 15:34:46 -07:00
Leijurv
baf27363aa fix movement ascend x z cardinal asymmetry, fixes #204 2018-10-02 15:02:27 -07:00
Leijurv
da137f35de fix parkour jumps ending on lilypads, fixes #203 2018-10-02 14:04:24 -07:00
Brady
feeeae5918 Add autotest directory to gitignore
If you're not using "autotest" as ur auto test "testing" directory, you SHOULD.
2018-10-02 15:28:20 -05:00
Brady
02a04773c6 bad javadocs 2018-10-02 15:27:25 -05:00
Brady
7e7b9f4fdb Make MemoryBehavior store data by world 2018-10-02 15:25:58 -05:00
Leijurv
85e4a57c76 no longer needed since goal is in api which in unobfed 2018-10-02 10:19:14 -07:00
Leijurv
6fd7b2a7f3 fix proguard for service provider 2018-10-02 10:17:56 -07:00
Leijurv
24be1d0ff3 lookahead a little more 2018-10-02 10:01:54 -07:00
Leijurv
2867e0626f reenable diagonal through water 2018-10-02 09:59:07 -07:00
Leijurv
f0c3e59a6f move from todo to issue 2018-10-01 22:50:51 -07:00
Leijurv
4e11d92d19 fix parkour cost calculation 2018-10-01 19:23:13 -07:00
Leijurv
07eee481cb fix failure on repeated descend 2018-10-01 15:42:16 -07:00
Leijurv
8f146d1a2b increase degree of backtrack cost favoring 2018-10-01 15:35:18 -07:00
Leijurv
1cc03e3aca it doesn't actually have to be falling, it just has to be solid 2018-10-01 15:20:52 -07:00
Leijurv
023822b5d9 stop breaking block on cancel, even if not requested by player 2018-10-01 15:11:52 -07:00
Leijurv
41ffd4455d don't cancel for any reason while doing a water bucket fall, fixes #98, fixes #123 2018-10-01 14:50:20 -07:00
Leijurv
810b92fbad Merge pull request #193 from cabaletta/service-loader
Service loader
2018-10-01 14:37:15 -07:00
Leijurv
6db31cbe74 now that that's fixed, we can tighten the maximum time again 2018-10-01 14:37:01 -07:00
Leijurv
b55a102d37 take depth strider into acocunt for water speed, fixes #101 2018-10-01 14:26:55 -07:00
Leijurv
f338cdd2e5 clear all keys including sprint in the next movement, fixes #194 2018-10-01 14:26:08 -07:00
Leijurv
76365a4564 sprint on soul sand, fixes #120 2018-10-01 10:05:04 -07:00
Leijurv
109cffc3de rearrange blockstate lookups 2018-10-01 09:57:47 -07:00
Leijurv
c67339dc42 Merge branch 'master' into service-loader 2018-10-01 09:53:03 -07:00
Leijurv
f56766be26 maybe it just needs more time 2018-10-01 09:51:43 -07:00
Leijurv
b1e1cc43e0 simplify properly even when obfuscated 2018-09-30 21:43:07 -07:00
Leijurv
13aaec07cd draw most recent node considered even if there is no valid best 2018-09-30 21:42:34 -07:00
Leijurv
08b9eab9f3 draw most recent node considered even if there is no valid best 2018-09-30 21:32:13 -07:00
Leijurv
09ac3c615c more time maybe 2018-09-30 09:14:23 -07:00
Leijurv
19ce1cf4a7 Merge branch 'master' into service-loader 2018-09-30 08:08:46 -07:00
Leijurv
d58ad6f68f finalize 2018-09-30 08:03:33 -07:00
Leijurv
866648192b readd width and height override 2018-09-30 07:58:44 -07:00
Brady
3184eaf595 Remove IBaritoneProvider#getSettings 2018-09-29 23:59:32 -05:00
Brady
b12c2ea62f UTILIZE Service Loaders
https://i.imgur.com/kAm0xd3.png
2018-09-29 23:52:01 -05:00
Leijurv
bcb95c55c9 allow a bit more time, it's a little flaky on travis right now 2018-09-29 07:43:34 -07:00
Leijurv
229739575c BaritoneAutoTest overrides width and height on its own 2018-09-29 07:32:58 -07:00
Leijurv
4b76af2487 update settings link 2018-09-29 07:30:56 -07:00
Leijurv
c383186808 sprint through descend then ascend in the same direction, fixes #115 2018-09-28 18:55:04 -07:00
Leijurv
2f602f8718 no stop dont 2018-09-27 16:11:55 -07:00
Leijurv
015462eddb beg people not to disable chunk caching 2018-09-27 15:37:22 -07:00
Leijurv
de6d6c8714 cached chunks expiration setting, fixes #181 2018-09-27 15:19:55 -07:00
Leijurv
1b2304146b reorganized diagonal 2018-09-26 17:25:18 -07:00
Leijurv
f28cdc531f this will really help performance a lot 2018-09-26 15:34:06 -07:00
Leijurv
2aa4770b45 add settings for pathing hashmap 2018-09-26 15:01:14 -07:00
Brady
1d931a4bb6 lol epic 2018-09-26 16:21:53 -05:00
Leijurv
9094c712d6 only optimize game settings if we are going to be auto testing 2018-09-26 13:46:08 -07:00
Leijurv
40a3177ae7 no need to get that twice 2018-09-26 13:05:36 -07:00
Leijurv
8ef89a8c80 bump mixin 2018-09-26 12:43:00 -07:00
Leijurv
ceb9ad9aa8 retry failed dependency downloads 2018-09-26 12:40:53 -07:00
Leijurv
dec1877123 bump lwjgl 2018-09-26 12:36:07 -07:00
Leijurv
34aa7cb6b5 only 1.11 exists 2018-09-26 11:22:06 -07:00
Leijurv
730ebb0070 remove sources 2018-09-26 11:09:25 -07:00
Leijurv
c4a3820c6a Try in other order 2018-09-26 10:46:42 -07:00
Leijurv
d4a846a672 maybe fix 2018-09-26 10:18:08 -07:00
Leijurv
a125170840 fix proguard path 2018-09-26 10:12:23 -07:00
Leijurv
d5d1d65bf3 fix build failure on repeated runs 2018-09-26 10:07:44 -07:00
Leijurv
fb45d73406 fetch jars from gradle instead of dropbox, fixes #189 2018-09-26 10:06:52 -07:00
Leijurv
5ec3971380 should match build.gradle 2018-09-26 09:51:25 -07:00
Leijurv
63b6169475 renamed 1.12.2 to minecraft 1.12.2 2018-09-26 09:50:24 -07:00
Leijurv
ab0d713882 THX 0x22 2018-09-25 22:18:19 -07:00
Leijurv
19661cc99c it takes more time to go a longer distance what a wild concept 2018-09-25 22:07:51 -07:00
Leijurv
d58656571a thx 0x22 2018-09-25 21:58:22 -07:00
Leijurv
4900c76752 merge 2018-09-25 21:57:00 -07:00
Brady
d899ff7f7b 2 iq 2018-09-25 23:24:48 -05:00
Brady
36651553fe Increase max ticks accordingly
See last commit
2018-09-25 23:17:15 -05:00
Brady
d9596fcac9 Travis may actually take 10 seconds to load in 2018-09-25 23:16:20 -05:00
Leijurv
aa7b77b413 can't pause on lost focus in xvfb 2018-09-25 18:57:50 -07:00
Brady
b3f06c6fac Allow pause on lost focus 2018-09-25 20:54:33 -05:00
Brady
3483be4bed Sync framerate limit with tps in auto test 2018-09-25 20:43:49 -05:00
Brady
d7a0d26fd2 Optimize game settings for better travis performance 2018-09-25 20:31:54 -05:00
Brady
90666cdfc1 Plutie's Jenkins is back 2018-09-25 19:04:34 -05:00
Leijurv
3072de610c add release link 2018-09-25 16:17:32 -07:00
90 changed files with 3353 additions and 1415 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,8 @@
**/*.swp
run/
autotest/
dist/
# Gradle
build/

View File

@@ -6,12 +6,10 @@ services:
- docker
install:
- sudo apt-get update
- sudo apt-get install jshon
- docker build -t cabaletta/baritone .
- travis_retry docker build -t cabaletta/baritone .
script:
- docker run --name baritone cabaletta/baritone /bin/sh -c "set -e; /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 128x128x24 -ac +extension GLX +render; sh scripts/build.sh; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient"
- docker run --name baritone cabaletta/baritone /bin/sh -c "set -e; /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 128x128x24 -ac +extension GLX +render; DISPLAY=:99 BARITONE_AUTO_TEST=true ./gradlew runClient"
- docker cp baritone:/code/dist dist
- ls dist
- cat dist/checksums.txt

View File

@@ -13,12 +13,10 @@ RUN apt install --target-release jessie-backports \
RUN apt install -qq --force-yes mesa-utils libgl1-mesa-glx libxcursor1 libxrandr2 libxxf86vm1 x11-xserver-utils xfonts-base xserver-common
RUN apt install -qq --force-yes unzip wget
ADD . /code
RUN echo "\nrunClient {\nargs \"--width\",\"128\",\"--height\",\"128\"\n}" >> /code/build.gradle
COPY . /code
# this .deb is specially patched to support lwjgl
# source: https://github.com/tectonicus/tectonicus/issues/60#issuecomment-154239173
RUN dpkg -i /code/scripts/xvfb_1.16.4-1_amd64.deb
WORKDIR /code

View File

@@ -10,16 +10,19 @@
- **Falling blocks** Baritone understands the costs of breaking blocks with falling blocks on top, and includes all of their break costs. Additionally, since it avoids breaking any blocks touching a liquid, it won't break the bottom of a gravel stack below a lava lake (anymore).
- **Avoiding dangerous blocks** Obviously, it knows not to walk through fire or on magma, not to corner over lava (that deals some damage), not to break any blocks touching a liquid (it might drown), etc.
- **Parkour** Sprint jumping over 1, 2, or 3 block gaps
- **Parkour place** Sprint jumping over a 3 block gap and placing the block to land on while executing the jump. It's really cool.
# Pathing method
Baritone uses a modified version of A*.
Baritone uses A*, with some modifications:
- **Incremental cost backoff** Since most of the time Baritone only knows the terrain up to the render distance, it can't calculate a full path to the goal. Therefore it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit">write-up</a> that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
- **Segmented calculation** Traditional A* calculates until the most promising node is in the goal, however in the environment of Minecraft with a limited render distance, we don't know the environment all the way to our goal. Baritone has three possible ways for path calculation to end: finding a path all the way to the goal, running out of time, or getting to the render distance. In the latter two scenarios, the selection of which segment to actually execute falls to the next item (incremental cost backoff). Whenever the path calculation thread finds that the best / most promising node is at the edge of loaded chunks, it increments a counter. If this happens more than 50 times (configurable), path calculation exits early. This happens with very low render distances. Otherwise, calculation continues until the timeout is hit (also configurable) or we find a path all the way to the goal.
- **Incremental cost backoff** When path calculation exits early without getting all the way to the goal, Baritone it needs to select a segment to execute first (assuming it will calculate the next segment at the end of this one). It uses incremental cost backoff to select the best node by varying metrics, then paths to that node. This is unchanged from MineBot and I made a <a href="https://docs.google.com/document/d/1WVHHXKXFdCR1Oz__KtK8sFqyvSwJN_H4lftkHFgmzlc/edit">write-up</a> that still applies. In essence, it keeps track of the best node by various increasing coefficients, then picks the node with the least coefficient that goes at least 5 blocks from the starting position.
- **Minimum improvement repropagation** The pathfinder ignores alternate routes that provide minimal improvements (less than 0.01 ticks of improvement), because the calculation cost of repropagating this to all connected nodes is much higher than the half-millisecond path time improvement it would get.
- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment slightly, as a tiebreaker. This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. <a href="https://www.youtube.com/watch?v=CGiMcb8-99Y">Example</a>
- **Backtrack cost favoring** While calculating the next segment, Baritone favors backtracking its current segment. The cost is decreased heavily, but is still positive (this won't cause it to backtrack if it doesn't need to). This allows it to splice and jump onto the next segment as early as possible, if the next segment begins with a backtrack of the current one. <a href="https://www.youtube.com/watch?v=CGiMcb8-99Y">Example</a>
- **Backtrack detection and pausing** While path calculation happens on a separate thread, the main game thread has access to the latest node considered, and the best path so far (those are rendered light blue and dark blue respectively). When the current best path (rendered dark blue) passes through the player's current position on the current path segment, path execution is paused (if it's safe to do so), because there's no point continuing forward if we're about to turn around and go back that same way. Note that the current best path as reported by the path calculation thread takes into account the incremental cost backoff system, so it's accurate to what the path calculation thread will actually pick once it finishes.
# Configuring Baritone
All the settings and documentation are <a href="https://github.com/cabaletta/baritone/blob/master/src/main/java/baritone/Settings.java">here</a>.
All the settings and documentation are <a href="https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/Settings.java">here</a>.
To change a boolean setting, just say its name in chat (for example saying `allowBreak` toggles whether Baritone will consider breaking blocks). For a numeric setting, say its name then the new value (like `pathTimeoutMS 250`). It's case insensitive.
# Goals
@@ -30,6 +33,7 @@ The pathing goal can be set to any of these options:
- **GoalTwoBlocks** a block position that the player should stand in, either at foot or eye level
- **GoalGetToBlock** a block position that the player should stand adjacent to, below, or on top of
- **GoalNear** a block position that the player should get within a certain radius of, used for following entities
- **GoalAxis** a block position on an axis or diagonal axis (so x=0, z=0, or x=z), and y=120 (configurable)
And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one of which satisfies the goal. For example, `mine diamond_ore` creates a `GoalComposite` of `GoalTwoBlocks`s for every diamond ore location it knows of.
@@ -38,7 +42,6 @@ And finally `GoalComposite`. `GoalComposite` is a list of other goals, any one o
Things it doesn't have yet
- Trapdoors
- Sprint jumping in a 1x2 corridor
- Parkour (jumping over gaps of any length) [IN PROGRESS]
See <a href="https://github.com/cabaletta/baritone/issues">issues</a> for more.

View File

@@ -1,86 +1 @@
# Integration between Baritone and Impact
Impact 4.4 will have Baritone included on release, however, if you're impatient, you can install Baritone into Impact 4.3 right now!
## An Introduction
There are some basic steps to getting Baritone setup with Impact.
- Acquiring a build of Baritone
- Placing Baritone in the libraries directory
- Modifying the Impact Profile JSON to run baritone
- How to use Baritone
## Acquiring a build of Baritone
There are 3 methods of acquiring a build of Baritone (While it is still in development)
### Official Build (Not always up to date)
Download the "official" jar (as of commit <a href="https://github.com/cabaletta/baritone/commit/61cf103df451a5aafa6bfbe5ed089043212f0b42">61cf103</a>,
built on September 24) from <a href="https://www.dropbox.com/s/imc6xwwpwsh3i0y/baritone-1.0.0.jar?dl=0">here</a>.
### Building Baritone yourself
There are a few steps to this
- Clone this repository
- Setup the project as instructed in the README
- Run the ``build`` gradle task. You can either do this using IntelliJ's gradle UI or through a
command line
- Windows: ``gradlew build``
- Mac/Linux: ``./gradlew build``
- The build should be exported into ``/build/libs/baritone-X.Y.Z.jar``
### Cutting Edge Release
If you want to trust @Plutie#9079, you can download an automatically generated build of the latest commit
from his Jenkins server, found <a href="https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/">here</a>.
## Placing Baritone in the libraries directory
``/libraries`` is a neat directory in your <a href="https://minecraft.gamepedia.com/.minecraft">Minecraft Installation Directory</a>
that contains all of the dependencies that are required from the game and some mods. This is where we will be
putting baritone.
- Locate the ``libraries`` folder, it should be in the Minecraft Installation Directory
- Create 3 new subdirectories starting from ``libraries``
- ``cabaletta``
- ``baritone``
- ``X.Y.Z``
- Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder
- The full path should look like ``<Minecraft>/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar``
## Modifying the Impact Profile JSON to run baritone
The final step is "registering" the Baritone library with Impact, so that it loads on launch.
- Ensure your Minecraft launcher is closed
- Navigate back to the Minecraft Installation Directory
- Find the ``versions`` directory, and open in
- In here there should be a ``1.12.2-Impact_4.3`` folder.
- If you don't have any Impact folder or have a version older than 4.3, you can download Impact <a href="https://impactdevelopment.github.io">here</a>.
- Open the folder and inside there should be a file called ``1.12.2-Impact_4.3.json``
- Open the JSON file with a text editor that supports your system's line endings
- For example, Notepad on Windows likely will NOT work for this. You should instead use a Text Editor like
<a href="https://notepad-plus-plus.org/">Notepad++</a> if you're on Windows. (For other systems, I'm not sure
what would work the best so you may have to do some research.)
- Find the ``libraries`` array in the JSON. It should look something like this.
```
"libraries": [
{
"name": "net.minecraft:launchwrapper:1.12"
},
{
"name": "com.github.ImpactDevelopment:Impact:4.3-1.12.2",
"url": "https://impactdevelopment.github.io/maven/"
},
{
"name": "com.github.ImpactDeveloment:ClientAPI:3.0.2",
"url": "https://impactdevelopment.github.io/maven/"
},
...
```
- Create a new object in the array, between the ``Impact`` and ``ClientAPI`` dependencies preferably.
```
{
"name": "cabaletta:baritone:X.Y.Z"
},
```
- Now find the ``"minecraftArguments": "..."`` text near the top.
- At the very end of the quotes where it says ``--tweakClass clientapi.load.ClientTweaker"``, add on the following so it looks like:
- ``--tweakClass clientapi.load.ClientTweaker --tweakClass baritone.launch.BaritoneTweakerOptifine"``
- If you didn't close your launcher for this step, restart it now.
- You can now launch Impact 4.3 as normal, and Baritone should start up
## How to use Baritone
Instructions on how to use Baritone are limited, and you may have to read a little bit of code (Really nothing much
just plain English), you can view that <a href="https://github.com/cabaletta/baritone#chat-control">here</a>.
Impact 4.4 is out. See <a href="INSTALL.md">INSTALL.md</a>

98
INSTALL.md Normal file
View File

@@ -0,0 +1,98 @@
# Integration between Baritone and Impact
Impact 4.4 has Baritone included.
These instructions apply to Impact 4.3 (and potentially other hacked clients).
## An Introduction
There are some basic steps to getting Baritone setup with Impact.
- Acquiring a build of Baritone
- Placing Baritone in the libraries directory
- Modifying the Impact Profile JSON to run baritone
- How to use Baritone
## Acquiring a build of Baritone
There are 3 methods of acquiring a build of Baritone (While it is still in development)
### Official Release (Not always up to date)
https://github.com/cabaletta/baritone/releases
For Impact 4.3, there is no Baritone integration yet, so you will want `baritone-standalone-X.Y.Z.jar`.
Any official release will be GPG signed by leijurv (44A3EA646EADAC6A) and ZeroMemes (73A788379A197567). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by those two public keys of `checksums.txt`.
The build is fully deterministic and reproducible, and you can verify Travis did it properly by running `docker build --no-cache -t cabaletta/baritone . && docker run --rm cabaletta/baritone cat /code/dist/checksums.txt` yourself and comparing the shasum. This works identically on Travis, Mac, and Linux (if you have docker on Windows, I'd be grateful if you could let me know if it works there too).
### Building Baritone yourself
There are a few steps to this
- Clone this repository
- Setup the project as instructed in the README
- Run the ``build`` gradle task. You can either do this using IntelliJ's gradle UI or through a
command line
- Windows: ``gradlew build``
- Mac/Linux: ``./gradlew build``
- The build should be exported into ``/build/libs/baritone-X.Y.Z.jar``
### Cutting Edge Release
If you want to trust @Plutie#9079, you can download an automatically generated build of the latest commit
from his Jenkins server, found <a href="https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/">here</a>.
## Placing Baritone in the libraries directory
``/libraries`` is a neat directory in your <a href="https://minecraft.gamepedia.com/.minecraft">Minecraft Installation Directory</a>
that contains all of the dependencies that are required from the game and some mods. This is where we will be
putting baritone.
- Locate the ``libraries`` folder, it should be in the Minecraft Installation Directory
- Create 3 new subdirectories starting from ``libraries``
- ``cabaletta``
- ``baritone``
- ``X.Y.Z``
- Copy the build of Baritone that was acquired earlier, and place it into the ``X.Y.Z`` folder
- The full path should look like ``<Minecraft>/libraries/cabaletta/baritone/X.Y.Z/baritone-X.Y.Z.jar``
## Modifying the Impact Profile JSON to run baritone
The final step is "registering" the Baritone library with Impact, so that it loads on launch.
- Ensure your Minecraft launcher is closed
- Navigate back to the Minecraft Installation Directory
- Find the ``versions`` directory, and open in
- In here there should be a ``1.12.2-Impact_4.3`` folder.
- If you don't have any Impact folder or have a version older than 4.3, you can download Impact <a href="https://impactdevelopment.github.io">here</a>.
- Open the folder and inside there should be a file called ``1.12.2-Impact_4.3.json``
- Open the JSON file with a text editor that supports your system's line endings
- For example, Notepad on Windows likely will NOT work for this. You should instead use a Text Editor like
<a href="https://notepad-plus-plus.org/">Notepad++</a> if you're on Windows. (For other systems, I'm not sure
what would work the best so you may have to do some research.)
- Find the ``libraries`` array in the JSON. It should look something like this.
```
"libraries": [
{
"name": "net.minecraft:launchwrapper:1.12"
},
{
"name": "com.github.ImpactDevelopment:Impact:4.3-1.12.2",
"url": "https://impactdevelopment.github.io/maven/"
},
{
"name": "com.github.ImpactDeveloment:ClientAPI:3.0.2",
"url": "https://impactdevelopment.github.io/maven/"
},
...
```
- Create two new objects in the array, between the ``Impact`` and ``ClientAPI`` dependencies preferably.
```
{
"name": "cabaletta:baritone:X.Y.Z"
},
{
"name": "com.github.ImpactDevelopment:SimpleTweaker:1.1",
"url": "https://impactdevelopment.github.io/maven/"
},
```
- Now find the ``"minecraftArguments": "..."`` text near the top.
- At the very end of the quotes where it says ``--tweakClass clientapi.load.ClientTweaker"``, add on the following so it looks like:
- ``--tweakClass clientapi.load.ClientTweaker --tweakClass baritone.launch.BaritoneTweakerOptifine"``
- If you didn't close your launcher for this step, restart it now.
- You can now launch Impact 4.3 as normal, and Baritone should start up
## How to use Baritone
Instructions on how to use Baritone are limited, and you may have to read a little bit of code (Really nothing much
just plain English), you can view that <a href="https://github.com/cabaletta/baritone#chat-control">here</a>.

View File

@@ -1,23 +1,20 @@
# Baritone
[![Build Status](https://travis-ci.com/cabaletta/baritone.svg?branch=master)](https://travis-ci.com/cabaletta/baritone)
[![License](https://img.shields.io/github/license/cabaletta/baritone.svg)](LICENSE)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/7150d8ccf6094057b1782aa7a8f92d7d)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;utm_campaign=Badge_Grade)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400)](https://www.codacy.com/app/leijurv/baritone?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=cabaletta/baritone&amp;utm_campaign=Badge_Grade)
<!---
Plutie's jenkins is dead right now, so here's the old badge that was used:
[![Build Status](https://plutiejenkins.leijurv.com/job/baritone/badge/icon)](https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/)
--->
Unofficial Jenkins: [![Jenkins Status](https://img.shields.io/badge/jenkins-offline-red.svg)]()
<!-- Unofficial Jenkins: [![Build Status](https://plutiejenkins.leijurv.com/job/baritone/badge/icon)](https://plutiejenkins.leijurv.com/job/baritone/lastSuccessfulBuild/) -->
A Minecraft pathfinder bot. This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/),
the original version of the bot for Minecraft 1.8, rebuilt for 1.12.2. Baritone focuses on reliability and particularly performance (it's over [29x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths).
Baritone is the pathfinding system used in [Impact](https://impactdevelopment.github.io/) since 4.4.
Here are some links to help to get started:
- [Features](FEATURES.md)
- [Baritone + Impact](IMPACT.md)
- [Installation](INSTALL.md)
There's also some useful information down below
@@ -73,4 +70,4 @@ Magic. (Hours of [Leijurv](https://github.com/leijurv) enduring excruciating pai
## Why is it called Baritone?
It's named for FitMC's deep sultry voice.
It's named for FitMC's deep sultry voice.

View File

@@ -16,7 +16,7 @@
*/
group 'baritone'
version '0.0.3'
version '1.0.0'
buildscript {
repositories {
@@ -37,6 +37,10 @@ buildscript {
}
}
import baritone.gradle.task.CreateDistTask
import baritone.gradle.task.ProguardTask
apply plugin: 'java'
apply plugin: 'net.minecraftforge.gradle.tweaker-client'
apply plugin: 'org.spongepowered.mixin'
@@ -57,7 +61,9 @@ minecraft {
mappings = 'snapshot_20180731'
tweakClass = 'baritone.launch.BaritoneTweaker'
runDir = 'run'
makeObfSourceJar = false
// The sources jar should use SRG names not MCP to ensure compatibility with all mappings
makeObfSourceJar = true
}
repositories {
@@ -67,9 +73,15 @@ repositories {
name = 'spongepowered-repo'
url = 'http://repo.spongepowered.org/maven/'
}
maven {
name = 'impactdevelopment-repo'
url = 'https://impactdevelopment.github.io/maven/'
}
}
dependencies {
runtime launchCompile('com.github.ImpactDevelopment:SimpleTweaker:1.2')
runtime launchCompile('org.spongepowered:mixin:0.7.11-SNAPSHOT') {
// Mixin includes a lot of dependencies that are too up-to-date
exclude module: 'launchwrapper'
@@ -88,4 +100,16 @@ mixin {
jar {
from sourceSets.launch.output, sourceSets.api.output
preserveFileTimestamps = false
reproducibleFileOrder = true
}
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)
build.finalizedBy(createDist)

3
buildSrc/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
build/
.gradle/
out/

25
buildSrc/build.gradle Normal file
View File

@@ -0,0 +1,25 @@
/*
* 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/>.
*/
repositories {
mavenCentral()
}
dependencies {
compile group: 'com.google.code.gson', name: 'gson', version: '2.8.5'
compile group: 'commons-io', name: 'commons-io', version: '2.6'
}

View File

@@ -0,0 +1,102 @@
/*
* 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.task;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.gradle.api.DefaultTask;
import java.io.File;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
/**
* @author Brady
* @since 10/12/2018
*/
class BaritoneGradleTask extends DefaultTask {
static final JsonParser PARSER = new JsonParser();
static final String
PROGUARD_ZIP = "proguard.zip",
PROGUARD_JAR = "proguard.jar",
PROGUARD_CONFIG_TEMPLATE = "scripts/proguard.pro",
PROGUARD_CONFIG_DEST = "template.pro",
PROGUARD_API_CONFIG = "api.pro",
PROGUARD_STANDALONE_CONFIG = "standalone.pro",
PROGUARD_EXPORT_PATH = "proguard_out.jar",
VERSION_MANIFEST = "version_manifest.json",
TEMP_LIBRARY_DIR = "tempLibraries/",
ARTIFACT_STANDARD = "%s-%s.jar",
ARTIFACT_UNOPTIMIZED = "%s-unoptimized-%s.jar",
ARTIFACT_API = "%s-api-%s.jar",
ARTIFACT_STANDALONE = "%s-standalone-%s.jar";
String artifactName, artifactVersion;
Path artifactPath, artifactUnoptimizedPath, artifactApiPath, artifactStandalonePath, proguardOut;
void verifyArtifacts() throws Exception {
this.artifactName = getProject().getName();
this.artifactVersion = getProject().getVersion().toString();
this.artifactPath = this.getBuildFile(formatVersion(ARTIFACT_STANDARD));
this.artifactUnoptimizedPath = this.getBuildFile(formatVersion(ARTIFACT_UNOPTIMIZED));
this.artifactApiPath = this.getBuildFile(formatVersion(ARTIFACT_API));
this.artifactStandalonePath = this.getBuildFile(formatVersion(ARTIFACT_STANDALONE));
this.proguardOut = this.getTemporaryFile(PROGUARD_EXPORT_PATH);
if (!Files.exists(this.artifactPath)) {
throw new Exception("Artifact not found! Run build first!");
}
}
void write(InputStream stream, Path file) throws Exception {
if (Files.exists(file)) {
Files.delete(file);
}
Files.copy(stream, file);
}
String formatVersion(String string) {
return String.format(string, this.artifactName, this.artifactVersion);
}
Path getRelativeFile(String file) {
return Paths.get(new File(file).getAbsolutePath());
}
Path getTemporaryFile(String file) {
return Paths.get(new File(getTemporaryDir(), file).getAbsolutePath());
}
Path getBuildFile(String file) {
return getRelativeFile("build/libs/" + file);
}
JsonElement readJson(List<String> lines) {
return PARSER.parse(String.join("\n", lines));
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.task;
import org.gradle.api.tasks.TaskAction;
import javax.xml.bind.DatatypeConverter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.MessageDigest;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* @author Brady
* @since 10/12/2018
*/
public class CreateDistTask extends BaritoneGradleTask {
private static MessageDigest SHA1_DIGEST;
@TaskAction
protected void exec() throws Exception {
super.verifyArtifacts();
// Define the distribution file paths
Path api = getRelativeFile("dist/" + formatVersion(ARTIFACT_API));
Path standalone = getRelativeFile("dist/" + formatVersion(ARTIFACT_STANDALONE));
Path unoptimized = getRelativeFile("dist/" + formatVersion(ARTIFACT_UNOPTIMIZED));
// NIO will not automatically create directories
Path dir = getRelativeFile("dist/");
if (!Files.exists(dir)) {
Files.createDirectory(dir);
}
// Copy build jars to dist/
Files.copy(this.artifactApiPath, api, REPLACE_EXISTING);
Files.copy(this.artifactStandalonePath, standalone, REPLACE_EXISTING);
Files.copy(this.artifactUnoptimizedPath, unoptimized, REPLACE_EXISTING);
// Calculate all checksums and format them like "shasum"
List<String> shasum = Stream.of(api, standalone, unoptimized)
.map(path -> sha1(path) + " " + path.getFileName().toString())
.collect(Collectors.toList());
// Write the checksums to a file
Files.write(getRelativeFile("dist/checksums.txt"), shasum);
}
private static synchronized String sha1(Path path) {
try {
if (SHA1_DIGEST == null) {
SHA1_DIGEST = MessageDigest.getInstance("SHA-1");
}
return DatatypeConverter.printHexBinary(SHA1_DIGEST.digest(Files.readAllBytes(path))).toLowerCase();
} catch (Exception e) {
// haha no thanks
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,260 @@
/*
* 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.task;
import baritone.gradle.util.Determinizer;
import com.google.gson.*;
import org.apache.commons.io.IOUtils;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.gradle.internal.Pair;
import java.io.*;
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.zip.ZipEntry;
import java.util.zip.ZipFile;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
/**
* @author Brady
* @since 10/11/2018
*/
public class ProguardTask extends BaritoneGradleTask {
private static final Pattern TEMP_LIBRARY_PATTERN = Pattern.compile("-libraryjars 'tempLibraries\\/([a-zA-Z0-9/_\\-\\.]+)\\.jar'");
@Input
private String url;
@Input
private String extract;
@Input
private String versionManifest;
private Map<String, String> versionDownloadMap;
private List<String> requiredLibraries;
@TaskAction
protected void exec() throws Exception {
super.verifyArtifacts();
// "Haha brady why don't you make separate tasks"
processArtifact();
downloadProguard();
extractProguard();
generateConfigs();
downloadVersionManifest();
acquireDependencies();
proguardApi();
proguardStandalone();
cleanup();
}
private void processArtifact() throws Exception {
if (Files.exists(this.artifactUnoptimizedPath)) {
Files.delete(this.artifactUnoptimizedPath);
}
Determinizer.determinize(this.artifactPath.toString(), this.artifactUnoptimizedPath.toString());
}
private void downloadProguard() throws Exception {
Path proguardZip = getTemporaryFile(PROGUARD_ZIP);
if (!Files.exists(proguardZip)) {
write(new URL(this.url).openStream(), proguardZip);
}
}
private void extractProguard() throws Exception {
Path proguardJar = getTemporaryFile(PROGUARD_JAR);
if (!Files.exists(proguardJar)) {
ZipFile zipFile = new ZipFile(getTemporaryFile(PROGUARD_ZIP).toFile());
ZipEntry zipJarEntry = zipFile.getEntry(this.extract);
write(zipFile.getInputStream(zipJarEntry), proguardJar);
zipFile.close();
}
}
private void generateConfigs() throws Exception {
Files.copy(getRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), REPLACE_EXISTING);
// Setup the template that will be used to derive the API and Standalone configs
List<String> template = Files.readAllLines(getTemporaryFile(PROGUARD_CONFIG_DEST));
template.add(0, "-injars " + this.artifactPath.toString());
template.add(1, "-outjars " + this.getTemporaryFile(PROGUARD_EXPORT_PATH));
// Acquire the RT jar using "java -verbose". This doesn't work on Java 9+
Process p = new ProcessBuilder("java", "-verbose").start();
String out = IOUtils.toString(p.getInputStream(), "UTF-8").split("\n")[0].split("Opened ")[1].replace("]", "");
template.add(2, "-libraryjars '" + out + "'");
// API config doesn't require any changes from the changes that we made to the template
Files.write(getTemporaryFile(PROGUARD_API_CONFIG), template);
// For the Standalone config, don't keep the API package
List<String> standalone = new ArrayList<>(template);
standalone.removeIf(s -> s.contains("# this is the keep api"));
Files.write(getTemporaryFile(PROGUARD_STANDALONE_CONFIG), standalone);
// Discover all of the libraries that we will need to acquire from gradle
this.requiredLibraries = new ArrayList<>();
template.forEach(line -> {
if (!line.startsWith("#")) {
Matcher m = TEMP_LIBRARY_PATTERN.matcher(line);
if (m.find()) {
this.requiredLibraries.add(m.group(1));
}
}
});
}
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
// Likely a better way to do this, I just pair the dependency with the first valid configuration
Map<String, Pair<Configuration, Dependency>> dependencyLookupMap = new HashMap<>();
getProject().getConfigurations().stream().filter(Configuration::isCanBeResolved).forEach(config ->
config.getAllDependencies().forEach(dependency ->
dependencyLookupMap.putIfAbsent(dependency.getName() + "-" + dependency.getVersion(), Pair.of(config, dependency))));
// Create the directory if it doesn't already exist
Path tempLibraries = getTemporaryFile(TEMP_LIBRARY_DIR);
if (!Files.exists(tempLibraries)) {
Files.createDirectory(tempLibraries);
}
// 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);
}
continue;
}
// Find a configuration/dependency pair that matches the desired library
Pair<Configuration, Dependency> pair = null;
for (Map.Entry<String, Pair<Configuration, Dependency>> entry : dependencyLookupMap.entrySet()) {
if (entry.getKey().startsWith(lib)) {
pair = entry.getValue();
}
}
// The pair must be non-null
Objects.requireNonNull(pair);
// Find the library jar file, and copy it to tempLibraries
for (File file : pair.getLeft().files(pair.getRight())) {
if (file.getName().startsWith(lib)) {
Files.copy(file.toPath(), getTemporaryFile("tempLibraries/" + lib + ".jar"), REPLACE_EXISTING);
}
}
}
}
private void proguardApi() throws Exception {
runProguard(getTemporaryFile(PROGUARD_API_CONFIG));
Determinizer.determinize(this.proguardOut.toString(), this.artifactApiPath.toString());
}
private void proguardStandalone() throws Exception {
runProguard(getTemporaryFile(PROGUARD_STANDALONE_CONFIG));
Determinizer.determinize(this.proguardOut.toString(), this.artifactStandalonePath.toString());
}
private void cleanup() {
try {
Files.delete(this.proguardOut);
} catch (IOException ignored) {}
}
public void setUrl(String url) {
this.url = url;
}
public void setExtract(String extract) {
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)) {
Files.delete(this.proguardOut);
}
Path proguardJar = getTemporaryFile(PROGUARD_JAR);
Process p = new ProcessBuilder("java", "-jar", proguardJar.toString(), "@" + config.toString())
.directory(getTemporaryFile("").toFile()) // Set the working directory to the temporary folder]
.start();
// We can't do output inherit process I/O with gradle for some reason and have it work, so we have to do this
this.printOutputLog(p.getInputStream());
this.printOutputLog(p.getErrorStream());
// Halt the current thread until the process is complete, if the exit code isn't 0, throw an exception
int exitCode = p.waitFor();
if (exitCode != 0) {
throw new Exception("Proguard exited with code " + exitCode);
}
}
private void printOutputLog(InputStream stream) {
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (final Exception e) {
e.printStackTrace();
}
}).start();
}
}

View File

@@ -0,0 +1,143 @@
/*
* 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 com.google.gson.*;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.*;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
/**
* Make a .jar file deterministic by sorting all entries by name, and setting all the last modified times to 0.
* This makes the build 100% reproducible since the timestamp when you built it no longer affects the final file.
*
* @author leijurv
*/
public class Determinizer {
public static void determinize(String inputPath, String outputPath) throws IOException {
System.out.println("Running Determinizer");
System.out.println(" Input path: " + inputPath);
System.out.println(" Output path: " + outputPath);
try (
JarFile jarFile = new JarFile(new File(inputPath));
JarOutputStream jos = new JarOutputStream(new FileOutputStream(new File(outputPath)))
) {
List<JarEntry> entries = jarFile.stream()
.sorted(Comparator.comparing(JarEntry::getName))
.collect(Collectors.toList());
for (JarEntry entry : entries) {
if (entry.getName().equals("META-INF/fml_cache_annotation.json")) {
continue;
}
if (entry.getName().equals("META-INF/fml_cache_class_versions.json")) {
continue;
}
JarEntry clone = new JarEntry(entry.getName());
clone.setTime(42069);
jos.putNextEntry(clone);
if (entry.getName().endsWith(".refmap.json")) {
JsonObject object = new JsonParser().parse(new InputStreamReader(jarFile.getInputStream(entry))).getAsJsonObject();
jos.write(writeSorted(object).getBytes());
} else {
copy(jarFile.getInputStream(entry), jos);
}
}
jos.finish();
}
}
private static void copy(InputStream is, OutputStream os) throws IOException {
byte[] buffer = new byte[1024];
int len;
while ((len = is.read(buffer)) != -1) {
os.write(buffer, 0, len);
}
}
private static String writeSorted(JsonObject in) throws IOException {
StringWriter writer = new StringWriter();
JsonWriter jw = new JsonWriter(writer);
ORDERED_JSON_WRITER.write(jw, in);
return writer.toString() + "\n";
}
/**
* All credits go to GSON and its contributors. GSON is licensed under the Apache 2.0 License.
* This implementation has been modified to write {@link JsonObject} keys in order.
*
* @see <a href="https://github.com/google/gson/blob/master/LICENSE">GSON License</a>
* @see <a href="https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/bind/TypeAdapters.java#L698">Original Source</a>
*/
private static final TypeAdapter<JsonElement> ORDERED_JSON_WRITER = new TypeAdapter<JsonElement>() {
@Override
public JsonElement read(JsonReader in) {
return null;
}
@Override
public void write(JsonWriter out, JsonElement value) throws IOException {
if (value == null || value.isJsonNull()) {
out.nullValue();
} else if (value.isJsonPrimitive()) {
JsonPrimitive primitive = value.getAsJsonPrimitive();
if (primitive.isNumber()) {
out.value(primitive.getAsNumber());
} else if (primitive.isBoolean()) {
out.value(primitive.getAsBoolean());
} else {
out.value(primitive.getAsString());
}
} else if (value.isJsonArray()) {
out.beginArray();
for (JsonElement e : value.getAsJsonArray()) {
write(out, e);
}
out.endArray();
} else if (value.isJsonObject()) {
out.beginObject();
List<Map.Entry<String, JsonElement>> entries = new ArrayList<>(value.getAsJsonObject().entrySet());
entries.sort(Comparator.comparing(Map.Entry::getKey));
for (Map.Entry<String, JsonElement> e : entries) {
out.name(e.getKey());
write(out, e.getValue());
}
out.endObject();
} else {
throw new IllegalArgumentException("Couldn't write " + value.getClass());
}
}
};
}

View File

@@ -1,24 +0,0 @@
set -e # this makes the whole script fail immediately if any one of these commands fails
./gradlew build
export VERSION=$(cat build.gradle | grep "version '" | cut -d "'" -f 2-2)
wget -nv https://downloads.sourceforge.net/project/proguard/proguard/6.0/proguard6.0.3.zip
unzip proguard6.0.3.zip 2>&1 > /dev/null
cd build/libs
echo "-injars 'baritone-$VERSION.jar'" >> api.pro # insert current version
cat ../../scripts/proguard.pro | grep -v "this is the rt jar" | grep -v "\-injars" >> api.pro # remove default rt jar and injar lines
echo "-libraryjars '$(java -verbose 2>/dev/null | sed -ne '1 s/\[Opened \(.*\)\]/\1/p')'" >> api.pro # insert correct rt.jar location
tail api.pro # debug, print out what the previous two commands generated
cat api.pro | grep -v "\-keep class baritone.api" > standalone.pro # standalone doesn't keep baritone api
wget -nv https://www.dropbox.com/s/zmc2l3jnwdvzvak/tempLibraries.zip?dl=1 # i'm sorry
mv tempLibraries.zip?dl=1 tempLibraries.zip
unzip tempLibraries.zip
mkdir ../../dist
java -jar ../../proguard6.0.3/lib/proguard.jar @api.pro
mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-api-$VERSION.jar
java -jar ../../proguard6.0.3/lib/proguard.jar @standalone.pro
mv Obfuscated/baritone-$VERSION.jar ../../dist/baritone-standalone-$VERSION.jar
mv baritone-$VERSION.jar ../../dist/baritone-unoptimized-$VERSION.jar
cd ../../dist
shasum * | tee checksums.txt
cd ..

35
scripts/proguard.pro vendored
View File

@@ -1,7 +1,3 @@
-injars baritone-0.0.2.jar
-outjars Obfuscated
-keepattributes Signature
-keepattributes *Annotation*
@@ -12,14 +8,13 @@
-overloadaggressively
-dontusemixedcaseclassnames
# instead of obfing to a, b, c, obf to baritone.a, baritone.b, baritone.c so as to not conflict with minecraft's obfd classes
# instead of renaming to a, b, c, rename to baritone.a, baritone.b, baritone.c so as to not conflict with minecraft's obfd classes
-flattenpackagehierarchy
-repackageclasses 'baritone'
#-keep class baritone.behavior.** { *; }
-keep class baritone.api.** { *; }
#-keep class baritone.* { *; }
#-keep class baritone.pathing.goals.** { *; }
-keep class baritone.api.** { *; } # this is the keep api
-keep class baritone.BaritoneProvider
-keep class baritone.api.IBaritoneProvider
# setting names are reflected from field names, so keep field names
-keepclassmembers class baritone.api.Settings {
@@ -30,9 +25,10 @@
-keep class baritone.launch.** { *; }
# copy all necessary libraries into tempLibraries to build
-libraryjars '/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/rt.jar' # this is the rt jar
-libraryjars 'tempLibraries/1.12.2.jar'
-libraryjars 'tempLibraries/minecraft-1.12.2.jar'
-libraryjars 'tempLibraries/SimpleTweaker-1.2.jar'
-libraryjars 'tempLibraries/authlib-1.5.25.jar'
-libraryjars 'tempLibraries/codecjorbis-20101023.jar'
@@ -48,22 +44,21 @@
-libraryjars 'tempLibraries/httpclient-4.3.3.jar'
-libraryjars 'tempLibraries/httpcore-4.3.2.jar'
-libraryjars 'tempLibraries/icu4j-core-mojang-51.2.jar'
-libraryjars 'tempLibraries/java-objc-bridge-1.0.0-natives-osx.jar'
-libraryjars 'tempLibraries/java-objc-bridge-1.0.0.jar'
-libraryjars 'tempLibraries/jinput-2.0.5.jar'
-libraryjars 'tempLibraries/jinput-platform-2.0.5-natives-osx.jar'
-libraryjars 'tempLibraries/jna-4.4.0.jar'
-libraryjars 'tempLibraries/jopt-simple-5.0.3.jar'
-libraryjars 'tempLibraries/jsr305-3.0.1-sources.jar'
-libraryjars 'tempLibraries/jsr305-3.0.1.jar'
-libraryjars 'tempLibraries/jutils-1.0.0.jar'
-libraryjars 'tempLibraries/libraryjavasound-20101123.jar'
-libraryjars 'tempLibraries/librarylwjglopenal-20100824.jar'
-libraryjars 'tempLibraries/log4j-api-2.8.1.jar'
-libraryjars 'tempLibraries/log4j-core-2.8.1.jar'
-libraryjars 'tempLibraries/lwjgl-2.9.2-nightly-20140822.jar'
-libraryjars 'tempLibraries/lwjgl-platform-2.9.2-nightly-20140822-natives-osx.jar'
-libraryjars 'tempLibraries/lwjgl_util-2.9.2-nightly-20140822.jar'
# startsWith is used to check the library, and mac/linux differ in which version they use
# this is FINE
-libraryjars 'tempLibraries/lwjgl-.jar'
-libraryjars 'tempLibraries/lwjgl_util-.jar'
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
-libraryjars 'tempLibraries/oshi-core-1.1.jar'
-libraryjars 'tempLibraries/patchy-1.1.jar'
@@ -72,8 +67,8 @@
-libraryjars 'tempLibraries/soundsystem-20120107.jar'
-libraryjars 'tempLibraries/text2speech-1.10.3.jar'
-libraryjars 'tempLibraries/mixin-0.7.8-SNAPSHOT.jar'
-libraryjars 'tempLibraries/launchwrapper-1.12.jar'
-libraryjars 'tempLibraries/mixin-0.7.11-SNAPSHOT.jar'
-libraryjars 'tempLibraries/launchwrapper-1.11.jar' # TODO why does only 1.11.jar exist?

View File

@@ -19,6 +19,12 @@ package baritone.api;
import baritone.api.behavior.*;
import baritone.api.cache.IWorldProvider;
import baritone.api.cache.IWorldScanner;
import baritone.api.event.listener.IGameEventListener;
import baritone.api.utils.SettingsUtil;
import java.util.Iterator;
import java.util.ServiceLoader;
/**
* API exposure for various things implemented in Baritone.
@@ -28,37 +34,38 @@ import baritone.api.cache.IWorldProvider;
* @author Brady
* @since 9/23/2018
*/
public class BaritoneAPI {
public final class BaritoneAPI {
// General
private static final Settings settings = new Settings();
private static IWorldProvider worldProvider;
private static final IBaritoneProvider baritone;
private static final Settings settings;
// Behaviors
private static IFollowBehavior followBehavior;
private static ILookBehavior lookBehavior;
private static IMemoryBehavior memoryBehavior;
private static IMineBehavior mineBehavior;
private static IPathingBehavior pathingBehavior;
static {
ServiceLoader<IBaritoneProvider> baritoneLoader = ServiceLoader.load(IBaritoneProvider.class);
Iterator<IBaritoneProvider> instances = baritoneLoader.iterator();
baritone = instances.next();
settings = new Settings();
SettingsUtil.readAndApply(settings);
}
public static IFollowBehavior getFollowBehavior() {
return followBehavior;
return baritone.getFollowBehavior();
}
public static ILookBehavior getLookBehavior() {
return lookBehavior;
return baritone.getLookBehavior();
}
public static IMemoryBehavior getMemoryBehavior() {
return memoryBehavior;
return baritone.getMemoryBehavior();
}
public static IMineBehavior getMineBehavior() {
return mineBehavior;
return baritone.getMineBehavior();
}
public static IPathingBehavior getPathingBehavior() {
return pathingBehavior;
return baritone.getPathingBehavior();
}
public static Settings getSettings() {
@@ -66,34 +73,14 @@ public class BaritoneAPI {
}
public static IWorldProvider getWorldProvider() {
return worldProvider;
return baritone.getWorldProvider();
}
/**
* FOR INTERNAL USE ONLY
*/
public static void registerProviders(
IWorldProvider worldProvider
) {
BaritoneAPI.worldProvider = worldProvider;
public static IWorldScanner getWorldScanner() {
return baritone.getWorldScanner();
}
/**
* FOR INTERNAL USE ONLY
*/
// @formatter:off
public static void registerDefaultBehaviors(
IFollowBehavior followBehavior,
ILookBehavior lookBehavior,
IMemoryBehavior memoryBehavior,
IMineBehavior mineBehavior,
IPathingBehavior pathingBehavior
) {
BaritoneAPI.followBehavior = followBehavior;
BaritoneAPI.lookBehavior = lookBehavior;
BaritoneAPI.memoryBehavior = memoryBehavior;
BaritoneAPI.mineBehavior = mineBehavior;
BaritoneAPI.pathingBehavior = pathingBehavior;
public static void registerEventListener(IGameEventListener listener) {
baritone.registerEventListener(listener);
}
// @formatter:on
}

View File

@@ -0,0 +1,86 @@
/*
* 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;
import baritone.api.behavior.*;
import baritone.api.cache.IWorldProvider;
import baritone.api.cache.IWorldScanner;
import baritone.api.event.listener.IGameEventListener;
/**
* @author Brady
* @since 9/29/2018
*/
public interface IBaritoneProvider {
/**
* @see IFollowBehavior
*
* @return The {@link IFollowBehavior} instance
*/
IFollowBehavior getFollowBehavior();
/**
* @see ILookBehavior
*
* @return The {@link ILookBehavior} instance
*/
ILookBehavior getLookBehavior();
/**
* @see IMemoryBehavior
*
* @return The {@link IMemoryBehavior} instance
*/
IMemoryBehavior getMemoryBehavior();
/**
* @see IMineBehavior
*
* @return The {@link IMineBehavior} instance
*/
IMineBehavior getMineBehavior();
/**
* @see IPathingBehavior
*
* @return The {@link IPathingBehavior} instance
*/
IPathingBehavior getPathingBehavior();
/**
* @see IWorldProvider
*
* @return The {@link IWorldProvider} instance
*/
IWorldProvider getWorldProvider();
/**
* @see IWorldScanner
*
* @return The {@link IWorldScanner} instance
*/
IWorldScanner getWorldScanner();
/**
* Registers a {@link IGameEventListener} with Baritone's "event bus".
*
* @param listener The listener
*/
void registerEventListener(IGameEventListener listener);
}

View File

@@ -56,6 +56,13 @@ public class Settings {
*/
public Setting<Double> blockPlacementPenalty = new Setting<>(20D);
/**
* This is just a tiebreaker to make it less likely to break blocks if it can avoid it.
* For example, fire has a break cost of 0, this makes it nonzero, so all else being equal
* it will take an otherwise equivalent route that doesn't require it to put out fire.
*/
public Setting<Double> blockBreakAdditionalPenalty = new Setting<>(2D);
/**
* Allow Baritone to fall arbitrary distances and place a water bucket beneath it.
* Reliability: questionable.
@@ -149,7 +156,7 @@ public class Settings {
*
* @see <a href="https://github.com/cabaletta/baritone/issues/18">Issue #18</a>
*/
public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.9);
public Setting<Double> backtrackCostFavoringCoefficient = new Setting<>(0.5);
/**
* Don't repropagate cost improvements below 0.01 ticks. They're all just floating point inaccuracies,
@@ -191,7 +198,19 @@ public class Settings {
/**
* Start planning the next path once the remaining movements tick estimates sum up to less than this value
*/
public Setting<Integer> planningTickLookAhead = new Setting<>(100);
public Setting<Integer> planningTickLookAhead = new Setting<>(150);
/**
* Default size of the Long2ObjectOpenHashMap used in pathing
*/
public Setting<Integer> pathingMapDefaultSize = new Setting<>(1024);
/**
* Load factor coefficient for the Long2ObjectOpenHashMap used in pathing
* <p>
* Decrease for faster map operations, but higher memory usage
*/
public Setting<Float> pathingMapLoadFactor = new Setting<>(0.75f);
/**
* How far are you allowed to fall onto solid ground (without a water bucket)?
@@ -283,6 +302,21 @@ public class Settings {
*/
public Setting<Boolean> renderGoal = new Setting<>(true);
/**
* Ignore depth when rendering the goal
*/
public Setting<Boolean> renderGoalIgnoreDepth = new Setting<>(false);
/**
* Ignore depth when rendering the selection boxes (to break, to place, to walk into)
*/
public Setting<Boolean> renderSelectionBoxesIgnoreDepth = new Setting<>(false);
/**
* Ignore depth when rendering the path
*/
public Setting<Boolean> renderPathIgnoreDepth = new Setting<>(false);
/**
* Line width of the path when rendered, in pixels
*/
@@ -355,7 +389,7 @@ public class Settings {
* <p>
* Also on cosmic prisons this should be set to true since you don't actually mine the ore it just gets replaced with stone.
*/
public Setting<Boolean> cancelOnGoalInvalidation = new Setting<>(true);
public Setting<Boolean> cancelOnGoalInvalidation = new Setting<>(false);
/**
* The "axis" command (aka GoalAxis) will go to a axis, or diagonal axis, at this Y level.
@@ -392,6 +426,28 @@ public class Settings {
*/
public Setting<Integer> followRadius = new Setting<>(3);
/**
* Cached chunks (regardless of if they're in RAM or saved to disk) expire and are deleted after this number of seconds
* -1 to disable
* <p>
* I would highly suggest leaving this setting disabled (-1).
* <p>
* The only valid reason I can think of enable this setting is if you are extremely low on disk space and you play on multiplayer,
* and can't take (average) 300kb saved for every 512x512 area. (note that more complicated terrain is less compressible and will take more space)
* <p>
* However, simply discarding old chunks because they are old is inadvisable. Baritone is extremely good at correcting
* itself and its paths as it learns new information, as new chunks load. There is no scenario in which having an
* incorrect cache can cause Baritone to get stuck, take damage, or perform any action it wouldn't otherwise, everything
* is rechecked once the real chunk is in range.
* <p>
* Having a robust cache greatly improves long distance pathfinding, as it's able to go around large scale obstacles
* before they're in render distance. In fact, when the chunkCaching setting is disabled and Baritone starts anew
* every time, or when you enter a completely new and very complicated area, it backtracks far more often because it
* has to build up that cache from scratch. But after it's gone through an area just once, the next time will have zero
* backtracking, since the entire area is now known and cached.
*/
public Setting<Long> cachedChunksExpirySeconds = new Setting<>(-1L);
/**
* The function that is called when Baritone will log to chat. This function can be added to
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
@@ -439,11 +495,19 @@ public class Settings {
*/
public Setting<Color> colorGoalBox = new Setting<>(Color.GREEN);
/**
* A map of lowercase setting field names to their respective setting
*/
public final Map<String, Setting<?>> byLowerName;
/**
* A list of all settings
*/
public final List<Setting<?>> allSettings;
public class Setting<T> {
public T value;
public final T defaultValue;
private String name;
private final Class<T> klass;
@@ -453,6 +517,7 @@ public class Settings {
throw new IllegalArgumentException("Cannot determine value type class from null");
}
this.value = value;
this.defaultValue = value;
this.klass = (Class<T>) value.getClass();
}
@@ -476,7 +541,7 @@ public class Settings {
// here be dragons
{
Settings() {
Field[] temp = getClass().getFields();
HashMap<String, Setting<?>> tmpByName = new HashMap<>();
List<Setting<?>> tmpAll = new ArrayList<>();
@@ -511,6 +576,4 @@ public class Settings {
}
return result;
}
Settings() { }
}

View File

@@ -20,6 +20,8 @@ package baritone.api.behavior;
import baritone.api.behavior.memory.IRememberedInventory;
import net.minecraft.util.math.BlockPos;
import java.util.Map;
/**
* @author Brady
* @since 9/23/2018
@@ -33,4 +35,11 @@ public interface IMemoryBehavior extends IBehavior {
* @return The remembered inventory
*/
IRememberedInventory getInventoryByPos(BlockPos pos);
/**
* Gets the map of all block positions to their remembered inventories.
*
* @return Map of block positions to their respective remembered inventories
*/
Map<BlockPos, IRememberedInventory> getRememberedInventories();
}

View File

@@ -17,7 +17,10 @@
package baritone.api.behavior;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.path.IPathExecutor;
import java.util.Optional;
@@ -65,4 +68,30 @@ public interface IPathingBehavior extends IBehavior {
* Cancels the pathing behavior or the current path calculation.
*/
void cancel();
/**
* Returns the current path, from the current path executor, if there is one.
*
* @return The current path
*/
default Optional<IPath> getPath() {
return Optional.ofNullable(getCurrent()).map(IPathExecutor::getPath);
}
/**
* @return The current path finder being executed
*/
Optional<IPathFinder> getPathFinder();
/**
* @return The current path executor
*/
IPathExecutor getCurrent();
/**
* Returns the next path executor, created when planning ahead.
*
* @return The next path executor
*/
IPathExecutor getNext();
}

View File

@@ -0,0 +1,42 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.cache;
import net.minecraft.block.Block;
import net.minecraft.util.math.BlockPos;
import java.util.List;
/**
* @author Brady
* @since 10/6/2018
*/
public interface IWorldScanner {
/**
* Scans the world, up to the specified max chunk radius, for the specified blocks.
*
* @param blocks The blocks to scan for
* @param max The maximum number of blocks to scan before cutoff
* @param yLevelThreshold If a block is found within this Y level, the current result will be
* returned, if the value is negative, then this condition doesn't apply.
* @param maxSearchRadius The maximum chunk search radius
* @return The matching block positions
*/
List<BlockPos> scanChunkRadius(List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius);
}

View File

@@ -20,6 +20,8 @@ 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}.
*
* @author Brady
* @since 8/22/2018
*/

View File

@@ -17,20 +17,22 @@
package baritone.api.event.events;
import baritone.api.event.events.type.Cancellable;
import baritone.api.event.events.type.ManagedPlayerEvent;
import net.minecraft.client.entity.EntityPlayerSP;
/**
* @author Brady
* @since 8/1/2018 6:39 PM
*/
public final class ChatEvent extends Cancellable {
public final class ChatEvent extends ManagedPlayerEvent.Cancellable {
/**
* The message being sent
*/
private final String message;
public ChatEvent(String message) {
public ChatEvent(EntityPlayerSP player, String message) {
super(player);
this.message = message;
}

View File

@@ -18,6 +18,7 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.Packet;
/**
@@ -26,15 +27,22 @@ import net.minecraft.network.Packet;
*/
public final class PacketEvent {
private final NetworkManager networkManager;
private final EventState state;
private final Packet<?> packet;
public PacketEvent(EventState state, Packet<?> packet) {
public PacketEvent(NetworkManager networkManager, EventState state, Packet<?> packet) {
this.networkManager = networkManager;
this.state = state;
this.packet = packet;
}
public final NetworkManager getNetworkManager() {
return this.networkManager;
}
public final EventState getState() {
return this.state;
}

View File

@@ -18,19 +18,22 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
import baritone.api.event.events.type.ManagedPlayerEvent;
import net.minecraft.client.entity.EntityPlayerSP;
/**
* @author Brady
* @since 8/21/2018
*/
public final class PlayerUpdateEvent {
public final class PlayerUpdateEvent extends ManagedPlayerEvent {
/**
* The state of the event
*/
private final EventState state;
public PlayerUpdateEvent(EventState state) {
public PlayerUpdateEvent(EntityPlayerSP player, EventState state) {
super(player);
this.state = state;
}

View File

@@ -18,6 +18,8 @@
package baritone.api.event.events;
import baritone.api.event.events.type.EventState;
import baritone.api.event.events.type.ManagedPlayerEvent;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityLivingBase;
@@ -25,7 +27,7 @@ import net.minecraft.entity.EntityLivingBase;
* @author Brady
* @since 8/21/2018
*/
public final class RotationMoveEvent {
public final class RotationMoveEvent extends ManagedPlayerEvent {
/**
* The type of event
@@ -37,7 +39,8 @@ public final class RotationMoveEvent {
*/
private final EventState state;
public RotationMoveEvent(EventState state, Type type) {
public RotationMoveEvent(EntityPlayerSP player, EventState state, Type type) {
super(player);
this.state = state;
this.type = type;
}

View File

@@ -21,23 +21,19 @@ package baritone.api.event.events.type;
* @author Brady
* @since 8/1/2018 6:41 PM
*/
public class Cancellable {
public class Cancellable implements ICancellable {
/**
* Whether or not this event has been cancelled
*/
private boolean cancelled;
/**
* Cancels this event
*/
@Override
public final void cancel() {
this.cancelled = true;
}
/**
* @return Whether or not this event has been cancelled
*/
@Override
public final boolean isCancelled() {
return this.cancelled;
}

View File

@@ -15,20 +15,21 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
package baritone.api.event.events.type;
/**
* @author Brady
* @since 7/31/2018 10:10 PM
* @since 10/11/2018
*/
public class BaritoneTweakerOptifine extends BaritoneTweaker {
public interface ICancellable {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
/**
* Cancels this event
*/
void cancel();
/**
* @return Whether or not this event has been cancelled
*/
boolean isCancelled();
}

View File

@@ -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.api.event.events.type;
import net.minecraft.client.entity.EntityPlayerSP;
/**
* An event that has a reference to a locally managed player.
*
* @author Brady
* @since 10/11/2018
*/
public class ManagedPlayerEvent {
protected final EntityPlayerSP player;
public ManagedPlayerEvent(EntityPlayerSP player) {
this.player = player;
}
public final EntityPlayerSP getPlayer() {
return this.player;
}
public static class Cancellable extends ManagedPlayerEvent implements ICancellable {
/**
* Whether or not this event has been cancelled
*/
private boolean cancelled;
public Cancellable(EntityPlayerSP player) {
super(player);
}
@Override
public final void cancel() {
this.cancelled = true;
}
@Override
public final boolean isCancelled() {
return this.cancelled;
}
}
}

View File

@@ -15,37 +15,35 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.path;
package baritone.api.pathing.calc;
import baritone.Baritone;
import baritone.api.Settings;
import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.Movement;
import baritone.utils.Helper;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos;
import java.util.List;
/**
* @author leijurv
* @author leijurv, Brady
*/
public interface IPath extends Helper {
public interface IPath {
/**
* Ordered list of movements to carry out.
* movements.get(i).getSrc() should equal positions.get(i)
* movements.get(i).getDest() should equal positions.get(i+1)
* movements.size() should equal positions.size()-1
*
* @return All of the movements to carry out
*/
List<Movement> movements();
List<IMovement> movements();
/**
* All positions along the way.
* Should begin with the same as getSrc and end with the same as getDest
*
* @return All of the positions along this path
*/
List<BetterBlockPos> positions();
@@ -53,10 +51,10 @@ public interface IPath extends Helper {
* 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)
*/
default void postprocess() {}
default void postProcess() {}
/**
* Number of positions in this path
* Returns the number of positions in this path. Equivalent to {@code positions().size()}.
*
* @return Number of positions in this path
*/
@@ -65,74 +63,74 @@ public interface IPath extends Helper {
}
/**
* What goal was this path calculated towards?
*
* @return
* @return The goal that this path was calculated towards
*/
Goal getGoal();
default Tuple<Double, BlockPos> closestPathPos() {
double best = -1;
BlockPos bestPos = null;
for (BlockPos pos : positions()) {
double dist = Utils.playerDistanceToCenter(pos);
if (dist < best || best == -1) {
best = dist;
bestPos = pos;
}
}
return new Tuple<>(best, bestPos);
}
/**
* Returns the number of nodes that were considered during calculation before
* this path was found.
*
* @return The number of nodes that were considered before finding this path
*/
int getNumNodesConsidered();
/**
* Where does this path start
* Returns the start position of this path. This is the first element in the
* {@link List} that is returned by {@link IPath#positions()}.
*
* @return The start position of this path
*/
default BetterBlockPos getSrc() {
return positions().get(0);
}
/**
* Where does this path end
* Returns the end position of this path. This is the last element in the
* {@link List} that is returned by {@link IPath#positions()}.
*
* @return The end position of this path.
*/
default BetterBlockPos getDest() {
List<BetterBlockPos> pos = positions();
return pos.get(pos.size() - 1);
}
/**
* Returns the estimated number of ticks to complete the path from the given node index.
*
* @param pathPosition The index of the node we're calculating from
* @return The estimated number of ticks remaining frm the given position
*/
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(null);
sum += movements().get(i).getCost();
}
return sum;
}
int getNumNodesConsidered();
/**
* Cuts off this path at the loaded chunk border, and returns the resulting path. Default
* implementation just returns this path, without the intended functionality.
*
* @return The result of this cut-off operation
*/
default IPath cutoffAtLoadedChunks() {
for (int i = 0; i < positions().size(); i++) {
BlockPos pos = positions().get(i);
if (Minecraft.getMinecraft().world.getChunk(pos) instanceof EmptyChunk) {
logDebug("Cutting off path at edge of loaded chunks");
logDebug("Length decreased by " + (positions().size() - i - 1));
return new CutoffPath(this, i);
}
}
logDebug("Path ends within loaded chunks");
return this;
}
/**
* 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.
*
* @see Settings#pathCutoffMinimumLength
* @see Settings#pathCutoffFactor
*
* @return The result of this cut-off operation
*/
default IPath staticCutoff(Goal destination) {
if (length() < Baritone.settings().pathCutoffMinimumLength.get()) {
return this;
}
if (destination == null || destination.isInGoal(getDest())) {
return this;
}
double factor = Baritone.settings().pathCutoffFactor.get();
int newLength = (int) (length() * factor);
logDebug("Static cutoff " + length() + " to " + newLength);
return new CutoffPath(this, newLength);
return this;
}
}

View File

@@ -15,11 +15,9 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.calc;
package baritone.api.pathing.calc;
import baritone.api.pathing.goals.Goal;
import baritone.pathing.path.IPath;
import net.minecraft.util.math.BlockPos;
import java.util.Optional;
@@ -30,8 +28,6 @@ import java.util.Optional;
*/
public interface IPathFinder {
BlockPos getStart();
Goal getGoal();
/**

View File

@@ -23,21 +23,21 @@ public interface ActionCosts {
* These costs are measured roughly in ticks btw
*/
double WALK_ONE_BLOCK_COST = 20 / 4.317; // 4.633
double WALK_ONE_IN_WATER_COST = 20 / 2.2;
double WALK_ONE_IN_WATER_COST = 20 / 2.2; // 9.091
double WALK_ONE_OVER_SOUL_SAND_COST = WALK_ONE_BLOCK_COST * 2; // 0.4 in BlockSoulSand but effectively about half
double SPRINT_ONE_OVER_SOUL_SAND_COST = WALK_ONE_OVER_SOUL_SAND_COST * 0.75;
double LADDER_UP_ONE_COST = 20 / 2.35;
double LADDER_DOWN_ONE_COST = 20 / 3.0;
double SNEAK_ONE_BLOCK_COST = 20 / 1.3;
double LADDER_UP_ONE_COST = 20 / 2.35; // 8.511
double LADDER_DOWN_ONE_COST = 20 / 3.0; // 6.667
double SNEAK_ONE_BLOCK_COST = 20 / 1.3; // 15.385
double SPRINT_ONE_BLOCK_COST = 20 / 5.612; // 3.564
double SPRINT_MULTIPLIER = SPRINT_ONE_BLOCK_COST / WALK_ONE_BLOCK_COST; // 0.769
/**
* To walk off an edge you need to walk 0.5 to the edge then 0.3 to start falling off
*/
double WALK_OFF_BLOCK_COST = WALK_ONE_BLOCK_COST * 0.8;
double WALK_OFF_BLOCK_COST = WALK_ONE_BLOCK_COST * 0.8; // 3.706
/**
* To walk the rest of the way to be centered on the new block
*/
double CENTER_AFTER_FALL_COST = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST;
double CENTER_AFTER_FALL_COST = WALK_ONE_BLOCK_COST - WALK_OFF_BLOCK_COST; // 0.927
/**
* don't make this Double.MAX_VALUE because it's added to other things, maybe other COST_INFs,

View File

@@ -0,0 +1,67 @@
/*
* 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.pathing.movement;
import baritone.api.utils.BetterBlockPos;
import net.minecraft.util.math.BlockPos;
import java.util.List;
/**
* @author Brady
* @since 10/8/2018
*/
public interface IMovement {
double getCost();
MovementStatus update();
/**
* Resets the current state status to {@link MovementStatus#PREPPING}
*/
void reset();
/**
* Resets the cache for special break, place, and walk into blocks
*/
void resetBlockCache();
/**
* @return Whether or not it is safe to cancel the current movement state
*/
boolean safeToCancel();
double recalculateCost();
double calculateCostWithoutCaching();
boolean calculatedWhileLoaded();
BetterBlockPos getSrc();
BetterBlockPos getDest();
BlockPos getDirection();
List<BlockPos> toBreak();
List<BlockPos> toPlace();
List<BlockPos> toWalkInto();
}

View File

@@ -0,0 +1,74 @@
/*
* 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.pathing.movement;
/**
* @author Brady
* @since 10/8/2018
*/
public enum MovementStatus {
/**
* We are preparing the movement to be executed. This is when any blocks obstructing the destination are broken.
*/
PREPPING(false),
/**
* We are waiting for the movement to begin, after {@link MovementStatus#PREPPING}.
*/
WAITING(false),
/**
* The movement is currently in progress, after {@link MovementStatus#WAITING}
*/
RUNNING(false),
/**
* The movement has been completed and we are at our destination
*/
SUCCESS(true),
/**
* There was a change in state between calculation and actual
* movement execution, and the movement has now become impossible.
*/
UNREACHABLE(true),
/**
* Unused
*/
FAILED(true),
/**
* "Unused"
*/
CANCELED(true);
/**
* Whether or not this status indicates a complete movement.
*/
private final boolean complete;
MovementStatus(boolean complete) {
this.complete = complete;
}
public final boolean isComplete() {
return this.complete;
}
}

View File

@@ -0,0 +1,29 @@
/*
* 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.pathing.path;
import baritone.api.pathing.calc.IPath;
/**
* @author Brady
* @since 10/8/2018
*/
public interface IPathExecutor {
IPath getPath();
}

View File

@@ -15,9 +15,8 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils.pathing;
package baritone.api.utils;
import baritone.pathing.calc.AbstractNodeCostSearch;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
@@ -36,14 +35,12 @@ public final class BetterBlockPos extends BlockPos {
public final int x;
public final int y;
public final int z;
public final long hashCode;
public BetterBlockPos(int x, int y, int z) {
super(x, y, z);
this.x = x;
this.y = y;
this.z = z;
this.hashCode = AbstractNodeCostSearch.posHash(x, y, z);
}
public BetterBlockPos(double x, double y, double z) {
@@ -56,7 +53,30 @@ public final class BetterBlockPos extends BlockPos {
@Override
public int hashCode() {
return (int) hashCode;
return (int) longHash(x, y, z);
}
public static long longHash(BetterBlockPos pos) {
return longHash(pos.x, pos.y, pos.z);
}
public static long longHash(int x, int y, int z) {
/*
* This is the hashcode implementation of Vec3i (the superclass of the class which I shall not name)
*
* public int hashCode() {
* return (this.getY() + this.getZ() * 31) * 31 + this.getX();
* }
*
* That is terrible and has tons of collisions and makes the HashMap terribly inefficient.
*
* That's why we grab out the X, Y, Z and calculate our own hashcode
*/
long hash = 3241;
hash = 3457689L * hash + x;
hash = 8734625L * hash + y;
hash = 2873465L * hash + z;
return hash;
}
@Override
@@ -66,9 +86,6 @@ public final class BetterBlockPos extends BlockPos {
}
if (o instanceof BetterBlockPos) {
BetterBlockPos oth = (BetterBlockPos) o;
if (oth.hashCode != hashCode) {
return false;
}
return oth.x == x && oth.y == y && oth.z == z;
}
// during path execution, like "if (whereShouldIBe.equals(whereAmI)) {"

View File

@@ -15,22 +15,29 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.utils;
package baritone.api.utils;
import baritone.api.utils.Rotation;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import static baritone.behavior.LookBehaviorUtils.calcVec3dFromRotation;
import java.util.Optional;
/**
* @author Brady
* @since 8/25/2018
*/
public final class RayTraceUtils implements Helper {
public final class RayTraceUtils {
private RayTraceUtils() {}
/**
* The {@link Minecraft} instance
*/
private static final Minecraft mc = Minecraft.getMinecraft();
/**
* Simulates a "vanilla" raytrace. A RayTraceResult returned by this method
* will be that of the next render pass given that the local player's yaw and
@@ -72,7 +79,7 @@ public final class RayTraceUtils implements Helper {
public static RayTraceResult rayTraceTowards(Rotation rotation) {
double blockReachDistance = mc.playerController.getBlockReachDistance();
Vec3d start = mc.player.getPositionEyes(1.0F);
Vec3d direction = calcVec3dFromRotation(rotation);
Vec3d direction = RotationUtils.calcVec3dFromRotation(rotation);
Vec3d end = start.add(
direction.x * blockReachDistance,
direction.y * blockReachDistance,
@@ -80,4 +87,28 @@ public final class RayTraceUtils implements Helper {
);
return mc.world.rayTraceBlocks(start, end, false, false, true);
}
/**
* Returns the block that the crosshair is currently placed over. Updated once per render tick.
*
* @return The position of the highlighted block
*/
public static Optional<BlockPos> getSelectedBlock() {
if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) {
return Optional.of(mc.objectMouseOver.getBlockPos());
}
return Optional.empty();
}
/**
* Returns the entity that the crosshair is currently placed over. Updated once per render tick.
*
* @return The entity
*/
public static Optional<Entity> getSelectedEntity() {
if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
return Optional.of(mc.objectMouseOver.entityHit);
}
return Optional.empty();
}
}

View File

@@ -17,6 +17,14 @@
package baritone.api.utils;
import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.*;
import java.util.Optional;
/**
* @author Brady
* @since 9/25/2018
@@ -25,6 +33,33 @@ public final class RotationUtils {
private RotationUtils() {}
/**
* The {@link Minecraft} instance
*/
private static final Minecraft mc = Minecraft.getMinecraft();
/**
* Constant that a degree value is multiplied by to get the equivalent radian value
*/
public static final double DEG_TO_RAD = Math.PI / 180.0;
/**
* Constant that a radian value is multiplied by to get the equivalent degree value
*/
public static final double RAD_TO_DEG = 180.0 / Math.PI;
/**
* Offsets from the root block position to the center of each side.
*/
private static final Vec3d[] BLOCK_SIDE_MULTIPLIERS = new Vec3d[]{
new Vec3d(0.5, 0, 0.5), // Down
new Vec3d(0.5, 1, 0.5), // Up
new Vec3d(0.5, 0.5, 0), // North
new Vec3d(0.5, 0.5, 1), // South
new Vec3d(0, 0.5, 0.5), // West
new Vec3d(1, 0.5, 0.5) // East
};
/**
* Clamps the specified pitch value between -90 and 90.
*
@@ -51,4 +86,156 @@ public final class RotationUtils {
}
return newYaw;
}
/**
* Calculates the rotation from BlockPos<sub>dest</sub> to BlockPos<sub>orig</sub>
*
* @param orig The origin position
* @param dest The destination position
* @return The rotation from the origin to the destination
*/
public static Rotation calcRotationFromCoords(BlockPos orig, BlockPos dest) {
return calcRotationFromVec3d(new Vec3d(orig), new Vec3d(dest));
}
/**
* Wraps the target angles to a relative value from the current angles. This is done by
* subtracting the current from the target, normalizing it, and then adding the current
* angles back to it.
*
* @param current The current angles
* @param target The target angles
* @return The wrapped angles
*/
public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) {
return target.subtract(current).normalize().add(current);
}
/**
* Calculates the rotation from Vec<sub>dest</sub> to Vec<sub>orig</sub> and makes the
* return value relative to the specified current rotations.
*
* @param orig The origin position
* @param dest The destination position
* @param current The current rotations
* @return The rotation from the origin to the destination
* @see #wrapAnglesToRelative(Rotation, Rotation)
*/
public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest, Rotation current) {
return wrapAnglesToRelative(current, calcRotationFromVec3d(orig, dest));
}
/**
* Calculates the rotation from Vec<sub>dest</sub> to Vec<sub>orig</sub>
*
* @param orig The origin position
* @param dest The destination position
* @return The rotation from the origin to the destination
*/
public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) {
double[] delta = {orig.x - dest.x, orig.y - dest.y, orig.z - dest.z};
double yaw = MathHelper.atan2(delta[0], -delta[2]);
double dist = Math.sqrt(delta[0] * delta[0] + delta[2] * delta[2]);
double pitch = MathHelper.atan2(delta[1], dist);
return new Rotation(
(float) (yaw * RAD_TO_DEG),
(float) (pitch * RAD_TO_DEG)
);
}
/**
* Calculates the look vector for the specified yaw/pitch rotations.
*
* @param rotation The input rotation
* @return Look vector for the rotation
*/
public static Vec3d calcVec3dFromRotation(Rotation rotation) {
float f = MathHelper.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
float f1 = MathHelper.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
float f2 = -MathHelper.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
float f3 = MathHelper.sin(-rotation.getPitch() * (float) DEG_TO_RAD);
return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
}
/**
* 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,
* that rotation will be returned. If not, it will return the first center of a given
* 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
* @return The optional rotation
*/
public static Optional<Rotation> reachable(Entity entity, BlockPos pos) {
if (pos.equals(RayTraceUtils.getSelectedBlock().orElse(null))) {
/*
* why add 0.0001?
* to indicate that we actually have a desired pitch
* the way we indicate that the pitch can be whatever and we only care about the yaw
* is by setting the desired pitch to the current pitch
* setting the desired pitch to the current pitch + 0.0001 means that we do have a desired pitch, it's
* just what it currently is
*/
return Optional.of(new Rotation(entity.rotationYaw, entity.rotationPitch + 0.0001F));
}
Optional<Rotation> possibleRotation = reachableCenter(entity, pos);
//System.out.println("center: " + possibleRotation);
if (possibleRotation.isPresent()) {
return possibleRotation;
}
IBlockState state = mc.world.getBlockState(pos);
AxisAlignedBB aabb = state.getBoundingBox(entity.world, pos);
for (Vec3d sideOffset : BLOCK_SIDE_MULTIPLIERS) {
double xDiff = aabb.minX * sideOffset.x + aabb.maxX * (1 - sideOffset.x);
double yDiff = aabb.minY * sideOffset.y + aabb.maxY * (1 - sideOffset.y);
double zDiff = aabb.minZ * sideOffset.z + aabb.maxZ * (1 - sideOffset.z);
possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff));
if (possibleRotation.isPresent()) {
return possibleRotation;
}
}
return Optional.empty();
}
/**
* Determines if the specified entity is able to reach the specified block with
* 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.
* @return The optional rotation
*/
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos) {
Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos);
RayTraceResult result = RayTraceUtils.rayTraceTowards(rotation);
//System.out.println(result);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
if (result.getBlockPos().equals(pos)) {
return Optional.of(rotation);
}
if (entity.world.getBlockState(pos).getBlock() instanceof BlockFire) {
if (result.getBlockPos().equals(pos.down())) {
return Optional.of(rotation);
}
}
}
return Optional.empty();
}
/**
* Determines if the specified entity is able to reach the specified block where it is
* looking at the direct center of it's hitbox.
*
* @param entity The viewing entity
* @param pos The target block position
* @return The optional rotation
*/
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos) {
return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(pos));
}
}

View File

@@ -0,0 +1,141 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.utils;
import baritone.api.Settings;
import net.minecraft.client.Minecraft;
import net.minecraft.item.Item;
import net.minecraft.util.ResourceLocation;
import java.awt.*;
import java.io.File;
import java.io.FileOutputStream;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SettingsUtil {
private static final File settingsFile = new File(new File(Minecraft.getMinecraft().gameDir, "baritone"), "settings.txt");
private static final Map<Class<?>, SettingsIO> map;
public static void readAndApply(Settings settings) {
try (Scanner scan = new Scanner(settingsFile)) {
while (scan.hasNextLine()) {
String line = scan.nextLine();
if (line.isEmpty()) {
continue;
}
if (line.startsWith("#") || line.startsWith("//")) {
continue;
}
int space = line.indexOf(" ");
if (space == -1) {
System.out.println("Skipping invalid line with no space: " + line);
continue;
}
String settingName = line.substring(0, space).trim().toLowerCase();
String settingValue = line.substring(space).trim();
try {
parseAndApply(settings, settingName, settingValue);
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Unable to parse line " + line);
}
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Exception while reading Baritone settings, some settings may be reset to default values!");
}
}
public static synchronized void save(Settings settings) {
try (FileOutputStream out = new FileOutputStream(settingsFile)) {
for (Settings.Setting setting : settings.allSettings) {
if (setting.get() == null) {
System.out.println("NULL SETTING?" + setting.getName());
continue;
}
if (setting.getName().equals("logger")) {
continue; // NO
}
if (setting.value == setting.defaultValue) {
continue;
}
SettingsIO io = map.get(setting.getValueClass());
if (io == null) {
throw new IllegalStateException("Missing " + setting.getValueClass() + " " + setting + " " + setting.getName());
}
out.write((setting.getName() + " " + io.toString.apply(setting.get()) + "\n").getBytes());
}
} catch (Exception ex) {
ex.printStackTrace();
System.out.println("Exception while saving Baritone settings!");
}
}
private static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
Settings.Setting setting = settings.byLowerName.get(settingName);
if (setting == null) {
throw new IllegalStateException("No setting by that name");
}
Class intendedType = setting.getValueClass();
SettingsIO ioMethod = map.get(intendedType);
Object parsed = ioMethod.parser.apply(settingValue);
if (!intendedType.isInstance(parsed)) {
throw new IllegalStateException(ioMethod + " parser returned incorrect type, expected " + intendedType + " got " + parsed + " which is " + parsed.getClass());
}
setting.value = parsed;
}
private enum SettingsIO {
DOUBLE(Double.class, Double::parseDouble),
BOOLEAN(Boolean.class, Boolean::parseBoolean),
INTEGER(Integer.class, Integer::parseInt),
FLOAT(Float.class, Float::parseFloat),
LONG(Long.class, Long::parseLong),
ITEM_LIST(ArrayList.class, str -> Stream.of(str.split(",")).map(Item::getByNameOrId).collect(Collectors.toCollection(ArrayList::new)), list -> ((ArrayList<Item>) list).stream().map(Item.REGISTRY::getNameForObject).map(ResourceLocation::toString).collect(Collectors.joining(","))),
COLOR(Color.class, str -> new Color(Integer.parseInt(str.split(",")[0]), Integer.parseInt(str.split(",")[1]), Integer.parseInt(str.split(",")[2])), color -> color.getRed() + "," + color.getGreen() + "," + color.getBlue());
Class<?> klass;
Function<String, Object> parser;
Function<Object, String> toString;
<T> SettingsIO(Class<T> klass, Function<String, T> parser) {
this(klass, parser, Object::toString);
}
<T> SettingsIO(Class<T> klass, Function<String, T> parser, Function<T, String> toString) {
this.klass = klass;
this.parser = parser::apply;
this.toString = x -> toString.apply((T) x);
}
}
static {
HashMap<Class<?>, SettingsIO> tempMap = new HashMap<>();
for (SettingsIO type : SettingsIO.values()) {
tempMap.put(type.klass, type);
}
map = Collections.unmodifiableMap(tempMap);
}
}

View File

@@ -0,0 +1,126 @@
/*
* 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.block.BlockFire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
/**
* @author Brady
* @since 10/13/2018
*/
public final class VecUtils {
private VecUtils() {}
/**
* The {@link Minecraft} instance
*/
private static final Minecraft mc = Minecraft.getMinecraft();
/**
* Calculates the center of the block at the specified position's bounding box
*
* @see #getBlockPosCenter(BlockPos)
*
* @param pos The block position
* @return The center of the block's bounding box
*/
public static Vec3d calculateBlockCenter(BlockPos pos) {
IBlockState b = mc.world.getBlockState(pos);
AxisAlignedBB bbox = b.getBoundingBox(mc.world, pos);
double xDiff = (bbox.minX + bbox.maxX) / 2;
double yDiff = (bbox.minY + bbox.maxY) / 2;
double zDiff = (bbox.minZ + bbox.maxZ) / 2;
if (b.getBlock() instanceof BlockFire) {//look at bottom of fire when putting it out
yDiff = 0;
}
return new Vec3d(
pos.getX() + xDiff,
pos.getY() + yDiff,
pos.getZ() + zDiff
);
}
/**
* Gets the assumed center position of the given block position.
* This is done by adding 0.5 to the X, Y, and Z axes.
* <p>
* TODO: We may want to consider replacing many usages of this method with #calculateBlockCenter(BlockPos)
*
* @see #calculateBlockCenter(BlockPos)
*
* @param pos The block position
* @return The assumed center of the position
*/
public static Vec3d getBlockPosCenter(BlockPos pos) {
return new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
}
/**
* Gets the distance from the specified position to the assumed center of the specified block position.
*
* @see #getBlockPosCenter(BlockPos)
*
* @param pos The block position
* @param x The x pos
* @param y The y pos
* @param z The z pos
* @return The distance from the assumed block center to the position
*/
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;
return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
}
/**
* Gets the distance from the specified entity's position to the assumed
* center of the specified block position.
*
* @see #getBlockPosCenter(BlockPos)
*
* @param entity The entity
* @param pos The block position
* @return The distance from the entity to the block's assumed center
*/
public static double entityDistanceToCenter(Entity entity, BlockPos pos) {
return distanceToCenter(pos, entity.posX, entity.posY, entity.posZ);
}
/**
* Gets the distance from the specified entity's position to the assumed
* center of the specified block position, ignoring the Y axis.
*
* @see #getBlockPosCenter(BlockPos)
*
* @param entity The entity
* @param pos The block position
* @return The horizontal distance from the entity to the block's assumed center
*/
public static double entityFlatDistanceToCenter(Entity entity, BlockPos pos) {
return distanceToCenter(pos, entity.posX, pos.getY() + 0.5, entity.posZ);
}
}

View File

@@ -17,61 +17,39 @@
package baritone.launch;
import net.minecraft.launchwrapper.ITweaker;
import io.github.impactdevelopment.simpletweaker.SimpleTweaker;
import net.minecraft.launchwrapper.Launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.launch.MixinBootstrap;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.asm.mixin.Mixins;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 9:59 PM
*/
public class BaritoneTweaker implements ITweaker {
List<String> args;
@Override
public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>(args);
if (gameDir != null) {
addArg("gameDir", gameDir.getAbsolutePath());
}
if (assetsDir != null) {
addArg("assetsDir", assetsDir.getAbsolutePath());
}
if (profile != null) {
addArg("version", profile);
}
}
public class BaritoneTweaker extends SimpleTweaker {
@Override
public void injectIntoClassLoader(LaunchClassLoader classLoader) {
super.injectIntoClassLoader(classLoader);
MixinBootstrap.init();
// noinspection unchecked
List<String> tweakClasses = (List<String>) Launch.blackboard.get("TweakClasses");
String obfuscation = ObfuscationServiceMCP.NOTCH;
if (tweakClasses.stream().anyMatch(s -> s.contains("net.minecraftforge.fml.common.launcher"))) {
obfuscation = ObfuscationServiceMCP.SEARGE;
}
MixinEnvironment.getDefaultEnvironment().setSide(MixinEnvironment.Side.CLIENT);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.NOTCH);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(obfuscation);
Mixins.addConfiguration("mixins.baritone.json");
}
@Override
public final String getLaunchTarget() {
return "net.minecraft.client.main.Main";
}
@Override
public final String[] getLaunchArguments() {
return this.args.toArray(new String[0]);
}
private void addArg(String label, String value) {
if (!args.contains("--" + label) && value != null) {
this.args.add("--" + label);
this.args.add(value);
}
}
}

View File

@@ -1,44 +0,0 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.launch;
import net.minecraft.launchwrapper.LaunchClassLoader;
import org.spongepowered.asm.mixin.MixinEnvironment;
import org.spongepowered.tools.obfuscation.mcp.ObfuscationServiceMCP;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* @author Brady
* @since 7/31/2018 10:09 PM
*/
public class BaritoneTweakerForge extends BaritoneTweaker {
@Override
public final void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) {
this.args = new ArrayList<>();
}
@Override
public final void injectIntoClassLoader(LaunchClassLoader classLoader) {
super.injectIntoClassLoader(classLoader);
MixinEnvironment.getDefaultEnvironment().setObfuscationContext(ObfuscationServiceMCP.SEARGE);
}
}

View File

@@ -20,7 +20,7 @@ package baritone.launch.mixins;
import baritone.Baritone;
import baritone.api.event.events.RotationMoveEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -40,8 +40,8 @@ public class MixinEntity {
)
private void preMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) {
Entity _this = (Entity) (Object) this;
if (_this == Minecraft.getMinecraft().player)
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent(EventState.PRE, RotationMoveEvent.Type.MOTION_UPDATE));
if (EntityPlayerSP.class.isInstance(_this))
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.PRE, RotationMoveEvent.Type.MOTION_UPDATE));
}
@Inject(
@@ -50,7 +50,7 @@ public class MixinEntity {
)
private void postMoveRelative(float strafe, float up, float forward, float friction, CallbackInfo ci) {
Entity _this = (Entity) (Object) this;
if (_this == Minecraft.getMinecraft().player)
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent(EventState.POST, RotationMoveEvent.Type.MOTION_UPDATE));
if (EntityPlayerSP.class.isInstance(_this))
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.POST, RotationMoveEvent.Type.MOTION_UPDATE));
}
}

View File

@@ -20,8 +20,7 @@ package baritone.launch.mixins;
import baritone.Baritone;
import baritone.api.event.events.RotationMoveEvent;
import baritone.api.event.events.type.EventState;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.Entity;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.EntityLivingBase;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
@@ -40,9 +39,9 @@ public class MixinEntityLivingBase {
at = @At("HEAD")
)
private void preJump(CallbackInfo ci) {
Entity _this = (Entity) (Object) this;
if (_this == Minecraft.getMinecraft().player)
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent(EventState.PRE, RotationMoveEvent.Type.JUMP));
EntityLivingBase _this = (EntityLivingBase) (Object) this;
if (EntityPlayerSP.class.isInstance(_this))
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.PRE, RotationMoveEvent.Type.JUMP));
}
@Inject(
@@ -50,8 +49,8 @@ public class MixinEntityLivingBase {
at = @At("RETURN")
)
private void postJump(CallbackInfo ci) {
Entity _this = (Entity) (Object) this;
if (_this == Minecraft.getMinecraft().player)
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent(EventState.POST, RotationMoveEvent.Type.JUMP));
EntityLivingBase _this = (EntityLivingBase) (Object) this;
if (EntityPlayerSP.class.isInstance(_this))
Baritone.INSTANCE.getGameEventHandler().onPlayerRotationMove(new RotationMoveEvent((EntityPlayerSP) _this, EventState.POST, RotationMoveEvent.Type.JUMP));
}
}

View File

@@ -40,7 +40,7 @@ public class MixinEntityPlayerSP {
cancellable = true
)
private void sendChatMessage(String msg, CallbackInfo ci) {
ChatEvent event = new ChatEvent(msg);
ChatEvent event = new ChatEvent((EntityPlayerSP) (Object) this, msg);
Baritone.INSTANCE.getGameEventHandler().onSendChatMessage(event);
if (event.isCancelled()) {
ci.cancel();
@@ -57,7 +57,7 @@ public class MixinEntityPlayerSP {
)
)
private void onPreUpdate(CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.PRE));
Baritone.INSTANCE.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent((EntityPlayerSP) (Object) this, EventState.PRE));
}
@Inject(
@@ -70,6 +70,6 @@ public class MixinEntityPlayerSP {
)
)
private void onPostUpdate(CallbackInfo ci) {
Baritone.INSTANCE.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent(EventState.POST));
Baritone.INSTANCE.getGameEventHandler().onPlayerUpdate(new PlayerUpdateEvent((EntityPlayerSP) (Object) this, EventState.POST));
}
}

View File

@@ -23,6 +23,7 @@ import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
import baritone.behavior.PathingBehavior;
import baritone.utils.BaritoneAutoTest;
import baritone.utils.ExampleBaritoneControl;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -59,11 +60,22 @@ public class MixinMinecraft {
method = "init",
at = @At("RETURN")
)
private void init(CallbackInfo ci) {
private void postInit(CallbackInfo ci) {
Baritone.INSTANCE.init();
ExampleBaritoneControl.INSTANCE.initAndRegister();
}
@Inject(
method = "init",
at = @At(
value = "INVOKE",
target = "net/minecraft/client/Minecraft.startTimerHackThread()V"
)
)
private void preInit(CallbackInfo ci) {
BaritoneAutoTest.INSTANCE.onPreInit();
}
@Inject(
method = "runTick",
at = @At(
@@ -135,7 +147,7 @@ public class MixinMinecraft {
)
)
private boolean isAllowUserInput(GuiScreen screen) {
return (PathingBehavior.INSTANCE.getCurrent() != null && player != null) || screen.allowUserInput;
return (PathingBehavior.INSTANCE.getCurrent() != null && PathingBehavior.INSTANCE.isEnabled() && player != null) || screen.allowUserInput;
}
@Inject(

View File

@@ -54,7 +54,7 @@ public class MixinNetworkManager {
)
private void preDispatchPacket(Packet<?> inPacket, final GenericFutureListener<? extends Future<? super Void>>[] futureListeners, CallbackInfo ci) {
if (this.direction == EnumPacketDirection.CLIENTBOUND) {
Baritone.INSTANCE.getGameEventHandler().onSendPacket(new PacketEvent(EventState.PRE, inPacket));
Baritone.INSTANCE.getGameEventHandler().onSendPacket(new PacketEvent((NetworkManager) (Object) this, EventState.PRE, inPacket));
}
}
@@ -64,7 +64,7 @@ public class MixinNetworkManager {
)
private void postDispatchPacket(Packet<?> inPacket, final GenericFutureListener<? extends Future<? super Void>>[] futureListeners, CallbackInfo ci) {
if (this.direction == EnumPacketDirection.CLIENTBOUND) {
Baritone.INSTANCE.getGameEventHandler().onSendPacket(new PacketEvent(EventState.POST, inPacket));
Baritone.INSTANCE.getGameEventHandler().onSendPacket(new PacketEvent((NetworkManager) (Object) this, EventState.POST, inPacket));
}
}
@@ -77,7 +77,7 @@ public class MixinNetworkManager {
)
private void preProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
if (this.direction == EnumPacketDirection.CLIENTBOUND) {
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent(EventState.PRE, packet));}
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent((NetworkManager) (Object) this, EventState.PRE, packet));}
}
@Inject(
@@ -86,7 +86,7 @@ public class MixinNetworkManager {
)
private void postProcessPacket(ChannelHandlerContext context, Packet<?> packet, CallbackInfo ci) {
if (this.channel.isOpen() && this.direction == EnumPacketDirection.CLIENTBOUND) {
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent(EventState.POST, packet));
Baritone.INSTANCE.getGameEventHandler().onReceivePacket(new PacketEvent((NetworkManager) (Object) this, EventState.POST, packet));
}
}
}

View File

@@ -21,7 +21,6 @@ import baritone.api.BaritoneAPI;
import baritone.api.Settings;
import baritone.api.event.listener.IGameEventListener;
import baritone.behavior.*;
import baritone.cache.WorldProvider;
import baritone.event.GameEventHandler;
import baritone.utils.BaritoneAutoTest;
import baritone.utils.InputOverrideHandler;
@@ -36,7 +35,6 @@ import java.util.concurrent.Executor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
/**
* @author Brady
@@ -61,19 +59,13 @@ public enum Baritone {
private File dir;
private ThreadPoolExecutor threadPool;
/**
* List of consumers to be called after Baritone has initialized
*/
private List<Consumer<Baritone>> onInitConsumers;
/**
* Whether or not Baritone is active
*/
private boolean active;
Baritone() {
this.onInitConsumers = new ArrayList<>();
this.gameEventHandler = new GameEventHandler();
}
public synchronized void init() {
@@ -81,15 +73,12 @@ public enum Baritone {
return;
}
this.threadPool = new ThreadPoolExecutor(4, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
this.gameEventHandler = new GameEventHandler();
this.inputOverrideHandler = new InputOverrideHandler();
// Acquire the "singleton" instance of the settings directly from the API
// We might want to change this...
this.settings = BaritoneAPI.getSettings();
BaritoneAPI.registerProviders(WorldProvider.INSTANCE);
this.behaviors = new ArrayList<>();
{
registerBehavior(PathingBehavior.INSTANCE);
@@ -98,19 +87,9 @@ public enum Baritone {
registerBehavior(LocationTrackingBehavior.INSTANCE);
registerBehavior(FollowBehavior.INSTANCE);
registerBehavior(MineBehavior.INSTANCE);
// TODO: Clean this up
// Maybe combine this call in someway with the registerBehavior calls?
BaritoneAPI.registerDefaultBehaviors(
FollowBehavior.INSTANCE,
LookBehavior.INSTANCE,
MemoryBehavior.INSTANCE,
MineBehavior.INSTANCE,
PathingBehavior.INSTANCE
);
}
if (BaritoneAutoTest.ENABLE_AUTO_TEST && "true".equals(System.getenv("BARITONE_AUTO_TEST"))) {
registerEventListener(new BaritoneAutoTest());
if (BaritoneAutoTest.ENABLE_AUTO_TEST) {
registerEventListener(BaritoneAutoTest.INSTANCE);
}
this.dir = new File(Minecraft.getMinecraft().gameDir, "baritone");
if (!Files.exists(dir.toPath())) {
@@ -121,8 +100,6 @@ public enum Baritone {
this.active = true;
this.initialized = true;
this.onInitConsumers.forEach(consumer -> consumer.accept(this));
}
public boolean isInitialized() {
@@ -169,8 +146,4 @@ public enum Baritone {
public File getDir() {
return this.dir;
}
public void registerInitListener(Consumer<Baritone> runnable) {
this.onInitConsumers.add(runnable);
}
}

View File

@@ -0,0 +1,74 @@
/*
* 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;
import baritone.api.IBaritoneProvider;
import baritone.api.behavior.*;
import baritone.api.cache.IWorldProvider;
import baritone.api.cache.IWorldScanner;
import baritone.api.event.listener.IGameEventListener;
import baritone.behavior.*;
import baritone.cache.WorldProvider;
import baritone.cache.WorldScanner;
/**
* @author Brady
* @since 9/29/2018
*/
public final class BaritoneProvider implements IBaritoneProvider {
@Override
public IFollowBehavior getFollowBehavior() {
return FollowBehavior.INSTANCE;
}
@Override
public ILookBehavior getLookBehavior() {
return LookBehavior.INSTANCE;
}
@Override
public IMemoryBehavior getMemoryBehavior() {
return MemoryBehavior.INSTANCE;
}
@Override
public IMineBehavior getMineBehavior() {
return MineBehavior.INSTANCE;
}
@Override
public IPathingBehavior getPathingBehavior() {
return PathingBehavior.INSTANCE;
}
@Override
public IWorldProvider getWorldProvider() {
return WorldProvider.INSTANCE;
}
@Override
public IWorldScanner getWorldScanner() {
return WorldScanner.INSTANCE;
}
@Override
public void registerEventListener(IGameEventListener listener) {
Baritone.INSTANCE.registerEventListener(listener);
}
}

View File

@@ -1,139 +0,0 @@
/*
* 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.api.utils.Rotation;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.RayTraceUtils;
import baritone.utils.Utils;
import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.*;
import java.util.Optional;
import static baritone.utils.Utils.DEG_TO_RAD;
public final class LookBehaviorUtils implements Helper {
/**
* Offsets from the root block position to the center of each side.
*/
private static final Vec3d[] BLOCK_SIDE_MULTIPLIERS = new Vec3d[]{
new Vec3d(0.5, 0, 0.5), // Down
new Vec3d(0.5, 1, 0.5), // Up
new Vec3d(0.5, 0.5, 0), // North
new Vec3d(0.5, 0.5, 1), // South
new Vec3d(0, 0.5, 0.5), // West
new Vec3d(1, 0.5, 0.5) // East
};
/**
* Calculates a vector given a rotation array
*
* @param rotation {@link LookBehavior#target}
* @return vector of the rotation
*/
public static Vec3d calcVec3dFromRotation(Rotation rotation) {
float f = MathHelper.cos(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
float f1 = MathHelper.sin(-rotation.getYaw() * (float) DEG_TO_RAD - (float) Math.PI);
float f2 = -MathHelper.cos(-rotation.getPitch() * (float) DEG_TO_RAD);
float f3 = MathHelper.sin(-rotation.getPitch() * (float) DEG_TO_RAD);
return new Vec3d((double) (f1 * f2), (double) f3, (double) (f * f2));
}
public static Optional<Rotation> reachable(BlockPos pos) {
if (pos.equals(getSelectedBlock().orElse(null))) {
/*
* why add 0.0001?
* to indicate that we actually have a desired pitch
* the way we indicate that the pitch can be whatever and we only care about the yaw
* is by setting the desired pitch to the current pitch
* setting the desired pitch to the current pitch + 0.0001 means that we do have a desired pitch, it's
* just what it currently is
*/
return Optional.of(new Rotation(mc.player.rotationYaw, mc.player.rotationPitch + 0.0001f));
}
Optional<Rotation> possibleRotation = reachableCenter(pos);
//System.out.println("center: " + possibleRotation);
if (possibleRotation.isPresent()) {
return possibleRotation;
}
IBlockState state = BlockStateInterface.get(pos);
AxisAlignedBB aabb = state.getBoundingBox(mc.world, pos);
for (Vec3d sideOffset : BLOCK_SIDE_MULTIPLIERS) {
double xDiff = aabb.minX * sideOffset.x + aabb.maxX * (1 - sideOffset.x);
double yDiff = aabb.minY * sideOffset.y + aabb.maxY * (1 - sideOffset.y);
double zDiff = aabb.minZ * sideOffset.z + aabb.maxZ * (1 - sideOffset.z);
possibleRotation = reachableOffset(pos, new Vec3d(pos).add(xDiff, yDiff, zDiff));
if (possibleRotation.isPresent()) {
return possibleRotation;
}
}
return Optional.empty();
}
/**
* Checks if coordinate is reachable with the given block-face rotation offset
*
* @param pos
* @param offsetPos
* @return
*/
protected static Optional<Rotation> reachableOffset(BlockPos pos, Vec3d offsetPos) {
Rotation rotation = Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F), offsetPos);
RayTraceResult result = RayTraceUtils.rayTraceTowards(rotation);
System.out.println(result);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
if (result.getBlockPos().equals(pos)) {
return Optional.of(rotation);
}
if (BlockStateInterface.get(pos).getBlock() instanceof BlockFire) {
if (result.getBlockPos().equals(pos.down())) {
return Optional.of(rotation);
}
}
}
return Optional.empty();
}
/**
* Checks if center of block at coordinate is reachable
*
* @param pos
* @return
*/
protected static Optional<Rotation> reachableCenter(BlockPos pos) {
return reachableOffset(pos, Utils.calcCenterFromCoords(pos, mc.world));
}
/**
* The currently highlighted block.
* Updated once a tick by Minecraft.
*
* @return the position of the highlighted block
*/
public static Optional<BlockPos> getSelectedBlock() {
if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.BLOCK) {
return Optional.of(mc.objectMouseOver.getBlockPos());
}
return Optional.empty();
}
}

View File

@@ -19,9 +19,11 @@ package baritone.behavior;
import baritone.api.behavior.IMemoryBehavior;
import baritone.api.behavior.memory.IRememberedInventory;
import baritone.api.cache.IWorldData;
import baritone.api.event.events.PacketEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.type.EventState;
import baritone.cache.WorldProvider;
import baritone.utils.Helper;
import net.minecraft.item.ItemStack;
import net.minecraft.network.Packet;
@@ -43,27 +45,19 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
public static MemoryBehavior INSTANCE = new MemoryBehavior();
/**
* 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 final Map<IWorldData, WorldDataContainer> worldDataContainers = new HashMap<>();
private MemoryBehavior() {}
@Override
public void onPlayerUpdate(PlayerUpdateEvent event) {
public synchronized void onPlayerUpdate(PlayerUpdateEvent event) {
if (event.getState() == EventState.PRE) {
updateInventory();
}
}
@Override
public void onSendPacket(PacketEvent event) {
public synchronized void onSendPacket(PacketEvent event) {
Packet p = event.getPacket();
if (event.getState() == EventState.PRE) {
@@ -78,7 +72,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
TileEntityLockable lockable = (TileEntityLockable) tileEntity;
int size = lockable.getSizeInventory();
this.futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), tileEntity.getPos()));
this.getCurrentContainer().futureInventories.add(new FutureInventory(System.nanoTime() / 1000000L, size, lockable.getGuiID(), tileEntity.getPos()));
}
}
@@ -89,24 +83,26 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
}
@Override
public void onReceivePacket(PacketEvent event) {
public synchronized void onReceivePacket(PacketEvent event) {
Packet p = event.getPacket();
if (event.getState() == EventState.PRE) {
if (p instanceof SPacketOpenWindow) {
SPacketOpenWindow packet = event.cast();
// Remove any entries that were created over a second ago, this should make up for INSANE latency
this.futureInventories.removeIf(i -> System.nanoTime() / 1000000L - i.time > 1000);
WorldDataContainer container = this.getCurrentContainer();
this.futureInventories.stream()
// 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);
container.futureInventories.stream()
.filter(i -> i.type.equals(packet.getGuiId()) && i.slots == packet.getSlotCount())
.findFirst().ifPresent(matched -> {
// Remove the future inventory
this.futureInventories.remove(matched);
container.futureInventories.remove(matched);
// Setup the remembered inventory
RememberedInventory inventory = this.rememberedInventories.computeIfAbsent(matched.pos, pos -> new RememberedInventory());
RememberedInventory inventory = container.rememberedInventories.computeIfAbsent(matched.pos, pos -> new RememberedInventory());
inventory.windowId = packet.getWindowId();
inventory.size = packet.getSlotCount();
});
@@ -119,7 +115,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
}
private Optional<RememberedInventory> getInventoryFromWindow(int windowId) {
return this.rememberedInventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
return this.getCurrentContainer().rememberedInventories.values().stream().filter(i -> i.windowId == windowId).findFirst();
}
private void updateInventory() {
@@ -129,9 +125,32 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
});
}
private WorldDataContainer getCurrentContainer() {
return this.worldDataContainers.computeIfAbsent(WorldProvider.INSTANCE.getCurrentWorld(), data -> new WorldDataContainer());
}
@Override
public final RememberedInventory getInventoryByPos(BlockPos pos) {
return this.rememberedInventories.get(pos);
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<>();
}
/**
@@ -170,7 +189,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
/**
* An inventory that we are aware of.
* <p>
* Associated with a {@link BlockPos} in {@link MemoryBehavior#rememberedInventories}.
* Associated with a {@link BlockPos} in {@link WorldDataContainer#rememberedInventories}.
*/
public static class RememberedInventory implements IRememberedInventory {
@@ -195,7 +214,7 @@ public final class MemoryBehavior extends Behavior implements IMemoryBehavior, H
@Override
public final List<ItemStack> getContents() {
return this.items;
return Collections.unmodifiableList(this.items);
}
@Override

View File

@@ -19,16 +19,15 @@ package baritone.behavior;
import baritone.Baritone;
import baritone.api.behavior.IMineBehavior;
import baritone.api.event.events.PathEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.pathing.goals.GoalComposite;
import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.cache.CachedChunk;
import baritone.cache.ChunkPacker;
import baritone.cache.WorldProvider;
import baritone.cache.WorldScanner;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.pathing.goals.GoalComposite;
import baritone.api.pathing.goals.GoalTwoBlocks;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import net.minecraft.block.Block;
@@ -78,59 +77,63 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe
int mineGoalUpdateInterval = Baritone.settings().mineGoalUpdateInterval.get();
if (mineGoalUpdateInterval != 0) {
if (event.getCount() % mineGoalUpdateInterval == 0) {
Baritone.INSTANCE.getExecutor().execute(this::updateGoal);
Baritone.INSTANCE.getExecutor().execute(this::rescan);
}
}
PathingBehavior.INSTANCE.revalidateGoal();
}
@Override
public void onPathEvent(PathEvent event) {
updateGoal();
PathingBehavior.INSTANCE.revalidateGoal();
}
private void updateGoal() {
if (mining == null) {
return;
}
if (!locationsCache.isEmpty()) {
locationsCache = prune(new ArrayList<>(locationsCache), mining, 64);
PathingBehavior.INSTANCE.setGoal(coalesce(locationsCache));
List<BlockPos> locs = locationsCache;
if (!locs.isEmpty()) {
locs = prune(new ArrayList<>(locs), mining, 64);
PathingBehavior.INSTANCE.setGoal(coalesce(locs));
PathingBehavior.INSTANCE.path();
locationsCache = locs;
}
}
private void rescan() {
if (mining == null) {
return;
}
List<BlockPos> locs = scanFor(mining, 64);
if (locs.isEmpty()) {
logDebug("No locations for " + mining + " known, cancelling");
cancel();
mine(0, (String[]) null);
return;
}
locationsCache = locs;
PathingBehavior.INSTANCE.setGoal(coalesce(locs));
PathingBehavior.INSTANCE.path();
}
public Goal coalesce(BlockPos loc, List<BlockPos> locs) {
if (!Baritone.settings().forceInternalMining.get()) {
return new GoalTwoBlocks(loc);
}
boolean upwardGoal = locs.contains(loc.up()) || (Baritone.settings().internalMiningAirException.get() && BlockStateInterface.getBlock(loc.up()) == Blocks.AIR);
boolean downwardGoal = locs.contains(loc.down()) || (Baritone.settings().internalMiningAirException.get() && BlockStateInterface.getBlock(loc.up()) == Blocks.AIR);
if (upwardGoal) {
if (downwardGoal) {
return new GoalTwoBlocks(loc);
} else {
return new GoalBlock(loc);
}
} else {
if (downwardGoal) {
return new GoalBlock(loc.down());
} else {
return new GoalTwoBlocks(loc);
}
}
}
public GoalComposite coalesce(List<BlockPos> locs) {
return new GoalComposite(locs.stream().map(loc -> {
if (!Baritone.settings().forceInternalMining.get()) {
return new GoalTwoBlocks(loc);
}
boolean upwardGoal = locs.contains(loc.up()) || (Baritone.settings().internalMiningAirException.get() && BlockStateInterface.getBlock(loc.up()) == Blocks.AIR);
boolean downwardGoal = locs.contains(loc.down()) || (Baritone.settings().internalMiningAirException.get() && BlockStateInterface.getBlock(loc.up()) == Blocks.AIR);
if (upwardGoal) {
if (downwardGoal) {
return new GoalTwoBlocks(loc);
} else {
return new GoalBlock(loc);
}
} else {
if (downwardGoal) {
return new GoalBlock(loc.down());
} else {
return new GoalTwoBlocks(loc);
}
}
}).toArray(Goal[]::new));
return new GoalComposite(locs.stream().map(loc -> coalesce(loc, locs)).toArray(Goal[]::new));
}
public List<BlockPos> scanFor(List<Block> mining, int max) {
@@ -150,7 +153,7 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe
}
if (!uninteresting.isEmpty()) {
//long before = System.currentTimeMillis();
locs.addAll(WorldScanner.INSTANCE.scanLoadedChunks(uninteresting, max, 10, 26));
locs.addAll(WorldScanner.INSTANCE.scanChunkRadius(uninteresting, max, 10, 26));
//System.out.println("Scan of loaded chunks took " + (System.currentTimeMillis() - before) + "ms");
}
return prune(locs, mining, max);
@@ -176,6 +179,7 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe
this.mining = blocks == null || blocks.length == 0 ? null : Arrays.stream(blocks).map(ChunkPacker::stringToBlock).collect(Collectors.toList());
this.quantity = quantity;
this.locationsCache = new ArrayList<>();
rescan();
updateGoal();
}
@@ -184,6 +188,7 @@ public final class MineBehavior extends Behavior implements IMineBehavior, Helpe
this.mining = blocks == null || blocks.length == 0 ? null : Arrays.asList(blocks);
this.quantity = quantity;
this.locationsCache = new ArrayList<>();
rescan();
updateGoal();
}

View File

@@ -23,28 +23,24 @@ import baritone.api.event.events.PathEvent;
import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.RenderEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalXZ;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.pathing.calc.AStarPathFinder;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.GoalXZ;
import baritone.pathing.calc.CutoffPath;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.path.IPath;
import baritone.pathing.path.PathExecutor;
import baritone.utils.BlockBreakHelper;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.PathRenderer;
import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Optional;
import java.util.*;
import java.util.stream.Collectors;
public final class PathingBehavior extends Behavior implements IPathingBehavior, Helper {
@@ -105,6 +101,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
dispatchPathEvent(PathEvent.CONTINUING_ONTO_PLANNED_NEXT);
current = next;
next = null;
current.onTick(event);
return;
}
// at this point, current just ended, but we aren't in the goal and have no plan for the future
@@ -123,12 +120,13 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (safe) {
// a movement just ended
if (next != null) {
if (next.getPath().positions().contains(playerFeet())) {
if (next.snipsnapifpossible()) {
// jump directly onto the next path
logDebug("Splicing into planned next path early...");
dispatchPathEvent(PathEvent.SPLICING_ONTO_NEXT_EARLY);
current = next;
next = null;
current.onTick(event);
return;
}
}
@@ -191,19 +189,19 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
return goal;
}
@Override
public PathExecutor getCurrent() {
return current;
}
@Override
public PathExecutor getNext() {
return next;
}
// TODO: Expose this method in the API?
// In order to do so, we'd need to move over IPath which has a whole lot of references to other
// things that may not need to be exposed necessarily, so we'll need to figure that out.
public Optional<IPath> getPath() {
return Optional.ofNullable(current).map(PathExecutor::getPath);
@Override
public Optional<IPathFinder> getPathFinder() {
return Optional.ofNullable(AbstractNodeCostSearch.currentlyRunning());
}
@Override
@@ -254,12 +252,46 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
}
/**
* See issue #209
*
* @return The starting {@link BlockPos} for a new path
*/
private BlockPos pathStart() {
public BlockPos pathStart() {
BetterBlockPos feet = playerFeet();
if (BlockStateInterface.get(feet.down()).getBlock().equals(Blocks.AIR) && MovementHelper.canWalkOn(feet.down().down())) {
return feet.down();
if (!MovementHelper.canWalkOn(feet.down())) {
if (player().onGround) {
double playerX = player().posX;
double playerZ = player().posZ;
ArrayList<BetterBlockPos> closest = new ArrayList<>();
for (int dx = -1; dx <= 1; dx++) {
for (int dz = -1; dz <= 1; dz++) {
closest.add(new BetterBlockPos(feet.x + dx, feet.y, feet.z + dz));
}
}
closest.sort(Comparator.comparingDouble(pos -> ((pos.x + 0.5D) - playerX) * ((pos.x + 0.5D) - playerX) + ((pos.z + 0.5D) - playerZ) * ((pos.z + 0.5D) - playerZ)));
for (int i = 0; i < 4; i++) {
BetterBlockPos possibleSupport = closest.get(i);
double xDist = Math.abs((possibleSupport.x + 0.5D) - playerX);
double zDist = Math.abs((possibleSupport.z + 0.5D) - playerZ);
if (xDist > 0.8 && zDist > 0.8) {
// can't possibly be sneaking off of this one, we're too far away
continue;
}
if (MovementHelper.canWalkOn(possibleSupport.down()) && MovementHelper.canWalkThrough(possibleSupport) && MovementHelper.canWalkThrough(possibleSupport.up())) {
// this is plausible
logDebug("Faking path start assuming player is standing off the edge of a block");
return possibleSupport;
}
}
} else {
// !onGround
// we're in the middle of a jump
if (MovementHelper.canWalkOn(feet.down().down())) {
logDebug("Faking path start assuming player is midair and falling");
return feet.down();
}
}
}
return feet;
}
@@ -284,9 +316,30 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
Optional<IPath> path = findPath(start, previous);
if (Baritone.settings().cutoffAtLoadBoundary.get()) {
path = path.map(IPath::cutoffAtLoadedChunks);
path = path.map(p -> {
IPath result = p.cutoffAtLoadedChunks();
if (result instanceof CutoffPath) {
logDebug("Cutting off path at edge of loaded chunks");
logDebug("Length decreased by " + (p.length() - result.length()));
} else {
logDebug("Path ends within loaded chunks");
}
return result;
});
}
Optional<PathExecutor> executor = path.map(p -> p.staticCutoff(goal)).map(PathExecutor::new);
Optional<PathExecutor> executor = path.map(p -> {
IPath result = p.staticCutoff(goal);
if (result instanceof CutoffPath) {
logDebug("Static cutoff " + p.length() + " to " + result.length());
}
return result;
}).map(PathExecutor::new);
synchronized (pathPlanLock) {
if (current == null) {
if (executor.isPresent()) {
@@ -341,7 +394,6 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
pos = ((IGoalRenderPos) goal).getGoalPos();
}
// TODO simplify each individual goal in a GoalComposite
if (pos != null && world().getChunk(pos) instanceof EmptyChunk) {
logDebug("Simplifying " + goal.getClass() + " to GoalXZ due to distance");
goal = new GoalXZ(pos.getX(), pos.getZ());
@@ -353,9 +405,14 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
} else {
timeout = Baritone.settings().planAheadTimeoutMS.<Long>get();
}
Optional<HashSet<Long>> favoredPositions = previous.map(IPath::positions).map(Collection::stream).map(x -> x.map(y -> y.hashCode)).map(x -> x.collect(Collectors.toList())).map(HashSet::new); // <-- okay this is EPIC
Optional<HashSet<Long>> favoredPositions;
if (Baritone.settings().backtrackCostFavoringCoefficient.get() == 1D) {
favoredPositions = Optional.empty();
} else {
favoredPositions = previous.map(IPath::positions).map(Collection::stream).map(x -> x.map(BetterBlockPos::longHash)).map(x -> x.collect(Collectors.toList())).map(HashSet::new); // <-- okay this is EPIC
}
try {
IPathFinder pf = new AStarPathFinder(start, goal, favoredPositions);
IPathFinder pf = new AStarPathFinder(start.getX(), start.getY(), start.getZ(), goal, favoredPositions);
return pf.calculate(timeout);
} catch (Exception e) {
logDebug("Pathing exception: " + e);
@@ -368,70 +425,23 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (!Baritone.settings().cancelOnGoalInvalidation.get()) {
return;
}
if (current == null || goal == null) {
return;
}
Goal intended = current.getPath().getGoal();
BlockPos end = current.getPath().getDest();
if (intended.isInGoal(end) && !goal.isInGoal(end)) {
// this path used to end in the goal
// but the goal has changed, so there's no reason to continue...
cancel();
synchronized (pathPlanLock) {
if (current == null || goal == null) {
return;
}
Goal intended = current.getPath().getGoal();
BlockPos end = current.getPath().getDest();
if (intended.isInGoal(end) && !goal.isInGoal(end)) {
// this path used to end in the goal
// but the goal has changed, so there's no reason to continue...
cancel();
}
}
}
@Override
public void onRenderPass(RenderEvent event) {
// System.out.println("Render passing");
// System.out.println(event.getPartialTicks());
float partialTicks = event.getPartialTicks();
if (goal != null && Baritone.settings().renderGoal.value) {
PathRenderer.drawLitDankGoalBox(player(), goal, partialTicks, Baritone.settings().colorGoalBox.get());
}
if (!Baritone.settings().renderPath.get()) {
return;
}
//long start = System.nanoTime();
PathExecutor current = this.current; // this should prevent most race conditions?
PathExecutor next = this.next; // like, now it's not possible for current!=null to be true, then suddenly false because of another thread
// TODO is this enough, or do we need to acquire a lock here?
// TODO benchmark synchronized in render loop
// Render the current path, if there is one
if (current != null && current.getPath() != null) {
int renderBegin = Math.max(current.getPosition() - 3, 0);
PathRenderer.drawPath(current.getPath(), renderBegin, player(), partialTicks, Baritone.settings().colorCurrentPath.get(), Baritone.settings().fadePath.get(), 10, 20);
}
if (next != null && next.getPath() != null) {
PathRenderer.drawPath(next.getPath(), 0, player(), partialTicks, Baritone.settings().colorNextPath.get(), Baritone.settings().fadePath.get(), 10, 20);
}
//long split = System.nanoTime();
if (current != null) {
PathRenderer.drawManySelectionBoxes(player(), current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get());
PathRenderer.drawManySelectionBoxes(player(), current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get());
PathRenderer.drawManySelectionBoxes(player(), current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get());
}
// If there is a path calculation currently running, render the path calculation process
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
currentlyRunning.bestPathSoFar().ifPresent(p -> {
PathRenderer.drawPath(p, 0, player(), partialTicks, Baritone.settings().colorBestPathSoFar.get(), Baritone.settings().fadePath.get(), 10, 20);
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
PathRenderer.drawPath(mr, 0, player(), partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20);
PathRenderer.drawManySelectionBoxes(player(), Collections.singletonList(mr.getDest()), partialTicks, Baritone.settings().colorMostRecentConsidered.get());
});
});
});
//long end = System.nanoTime();
//System.out.println((end - split) + " " + (split - start));
// if (end - start > 0) {
// System.out.println("Frame took " + (split - start) + " " + (end - split));
//}
PathRenderer.render(event, this);
}
@Override

View File

@@ -106,7 +106,9 @@ public final class CachedChunk implements IBlockTypeAccess, Helper {
private final Map<String, List<BlockPos>> specialBlockLocations;
CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map<String, List<BlockPos>> specialBlockLocations) {
public final long cacheTimestamp;
CachedChunk(int x, int z, BitSet data, IBlockState[] overview, Map<String, List<BlockPos>> specialBlockLocations, long cacheTimestamp) {
validateSize(data);
this.x = x;
@@ -115,6 +117,7 @@ public final class CachedChunk implements IBlockTypeAccess, Helper {
this.overview = overview;
this.heightMap = new int[256];
this.specialBlockLocations = specialBlockLocations;
this.cacheTimestamp = cacheTimestamp;
calculateHeightMap();
}

View File

@@ -17,6 +17,7 @@
package baritone.cache;
import baritone.Baritone;
import baritone.api.cache.ICachedRegion;
import net.minecraft.block.state.IBlockState;
import net.minecraft.util.math.BlockPos;
@@ -112,6 +113,7 @@ public final class CachedRegion implements ICachedRegion {
if (!hasUnsavedChanges) {
return;
}
removeExpired();
try {
Path path = Paths.get(directory);
if (!Files.exists(path)) {
@@ -129,8 +131,8 @@ public final class CachedRegion implements ICachedRegion {
DataOutputStream out = new DataOutputStream(gzipOut)
) {
out.writeInt(CACHED_REGION_MAGIC);
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
CachedChunk chunk = this.chunks[x][z];
if (chunk == null) {
out.write(CHUNK_NOT_PRESENT);
@@ -143,8 +145,8 @@ public final class CachedRegion implements ICachedRegion {
}
}
}
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (chunks[x][z] != null) {
for (int i = 0; i < 256; i++) {
out.writeUTF(ChunkPacker.blockToString(chunks[x][z].getOverview()[i].getBlock()));
@@ -152,8 +154,8 @@ public final class CachedRegion implements ICachedRegion {
}
}
}
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (chunks[x][z] != null) {
Map<String, List<BlockPos>> locs = chunks[x][z].getRelativeBlocks();
out.writeShort(locs.entrySet().size());
@@ -168,10 +170,17 @@ public final class CachedRegion implements ICachedRegion {
}
}
}
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (chunks[x][z] != null) {
out.writeLong(chunks[x][z].cacheTimestamp);
}
}
}
}
hasUnsavedChanges = false;
System.out.println("Saved region successfully");
} catch (IOException ex) {
} catch (Exception ex) {
ex.printStackTrace();
}
}
@@ -203,42 +212,42 @@ public final class CachedRegion implements ICachedRegion {
// by switching on the magic value, and either loading it normally, or loading through a converter.
throw new IOException("Bad magic value " + magic);
}
CachedChunk[][] tmpCached = new CachedChunk[32][32];
boolean[][] present = new boolean[32][32];
BitSet[][] bitSets = new BitSet[32][32];
Map<String, List<BlockPos>>[][] location = new Map[32][32];
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
IBlockState[][][] overview = new IBlockState[32][32][];
long[][] cacheTimestamp = new long[32][32];
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
int isChunkPresent = in.read();
switch (isChunkPresent) {
case CHUNK_PRESENT:
byte[] bytes = new byte[CachedChunk.SIZE_IN_BYTES];
in.readFully(bytes);
bitSets[x][z] = BitSet.valueOf(bytes);
location[x][z] = new HashMap<>();
int regionX = this.x;
int regionZ = this.z;
int chunkX = x + 32 * regionX;
int chunkZ = z + 32 * regionZ;
tmpCached[x][z] = new CachedChunk(chunkX, chunkZ, BitSet.valueOf(bytes), new IBlockState[256], location[x][z]);
overview[x][z] = new IBlockState[256];
present[x][z] = true;
break;
case CHUNK_NOT_PRESENT:
tmpCached[x][z] = null;
break;
default:
throw new IOException("Malformed stream");
}
}
}
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
if (tmpCached[x][z] != null) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (present[x][z]) {
for (int i = 0; i < 256; i++) {
tmpCached[x][z].getOverview()[i] = ChunkPacker.stringToBlock(in.readUTF()).getDefaultState();
overview[x][z][i] = ChunkPacker.stringToBlock(in.readUTF()).getDefaultState();
}
}
}
}
for (int z = 0; z < 32; z++) {
for (int x = 0; x < 32; x++) {
if (tmpCached[x][z] != null) {
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (present[x][z]) {
// 16 * 16 * 256 = 65536 so a short is enough
// ^ haha jokes on leijurv, java doesn't have unsigned types so that isn't correct
// also why would you have more than 32767 special blocks in a chunk
@@ -264,21 +273,67 @@ public final class CachedRegion implements ICachedRegion {
}
}
}
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (present[x][z]) {
cacheTimestamp[x][z] = in.readLong();
}
}
}
// only if the entire file was uncorrupted do we actually set the chunks
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
this.chunks[x][z] = tmpCached[x][z];
if (present[x][z]) {
int regionX = this.x;
int regionZ = this.z;
int chunkX = x + 32 * regionX;
int chunkZ = z + 32 * regionZ;
this.chunks[x][z] = new CachedChunk(chunkX, chunkZ, bitSets[x][z], overview[x][z], location[x][z], cacheTimestamp[x][z]);
}
}
}
}
removeExpired();
hasUnsavedChanges = false;
long end = System.nanoTime() / 1000000L;
System.out.println("Loaded region successfully in " + (end - start) + "ms");
} catch (IOException ex) {
} catch (Exception ex) { // corrupted files can cause NullPointerExceptions as well as IOExceptions
ex.printStackTrace();
}
}
public synchronized final void removeExpired() {
long expiry = Baritone.settings().cachedChunksExpirySeconds.get();
if (expiry < 0) {
return;
}
long now = System.currentTimeMillis();
long oldestAcceptableAge = now - expiry * 1000L;
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (this.chunks[x][z] != null && this.chunks[x][z].cacheTimestamp < oldestAcceptableAge) {
System.out.println("Removing chunk " + (x + 32 * this.x) + "," + (z + 32 * this.z) + " because it was cached " + (now - this.chunks[x][z].cacheTimestamp) / 1000L + " seconds ago, and max age is " + expiry);
this.chunks[x][z] = null;
}
}
}
}
public synchronized final CachedChunk mostRecentlyModified() {
CachedChunk recent = null;
for (int x = 0; x < 32; x++) {
for (int z = 0; z < 32; z++) {
if (this.chunks[x][z] == null) {
continue;
}
if (recent == null || this.chunks[x][z].cacheTimestamp > recent.cacheTimestamp) {
recent = this.chunks[x][z];
}
}
}
return recent;
}
/**
* @return The region x coordinate
*/

View File

@@ -142,6 +142,12 @@ public final class CachedWorld implements ICachedWorld, Helper {
public final void save() {
if (!Baritone.settings().chunkCaching.get()) {
System.out.println("Not saving to disk; chunk caching is disabled.");
allRegions().forEach(region -> {
if (region != null) {
region.removeExpired();
}
}); // even if we aren't saving to disk, still delete expired old chunks from RAM
prune();
return;
}
long start = System.nanoTime() / 1000000L;
@@ -152,6 +158,47 @@ public final class CachedWorld implements ICachedWorld, Helper {
});
long now = System.nanoTime() / 1000000L;
System.out.println("World save took " + (now - start) + "ms");
prune();
}
/**
* Delete regions that are too far from the player
*/
private synchronized void prune() {
BlockPos pruneCenter = guessPosition();
for (CachedRegion region : allRegions()) {
int distX = (region.getX() * 512 + 256) - pruneCenter.getX();
int distZ = (region.getZ() * 512 + 256) - pruneCenter.getZ();
double dist = Math.sqrt(distX * distX + distZ * distZ);
if (dist > 1024) {
logDebug("Deleting cached region " + region.getX() + "," + region.getZ() + " from ram");
cachedRegions.remove(getRegionID(region.getX(), region.getZ()));
}
}
}
/**
* If we are still in this world and dimension, return player feet, otherwise return most recently modified chunk
*/
private BlockPos guessPosition() {
WorldData data = WorldProvider.INSTANCE.getCurrentWorld();
if (data != null && data.getCachedWorld() == this) {
return playerFeet();
}
CachedChunk mostRecentlyModified = null;
for (CachedRegion region : allRegions()) {
CachedChunk ch = region.mostRecentlyModified();
if (ch == null) {
continue;
}
if (mostRecentlyModified == null || mostRecentlyModified.cacheTimestamp < ch.cacheTimestamp) {
mostRecentlyModified = ch;
}
}
if (mostRecentlyModified == null) {
return new BlockPos(0, 0, 0);
}
return new BlockPos(mostRecentlyModified.x * 16 + 8, 0, mostRecentlyModified.z * 16 + 8);
}
private synchronized List<CachedRegion> allRegions() {

View File

@@ -106,7 +106,7 @@ public final class ChunkPacker implements Helper {
blocks[z << 4 | x] = Blocks.AIR.getDefaultState();
}
}
return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks);
return new CachedChunk(chunk.x, chunk.z, bitSet, blocks, specialBlocks, System.currentTimeMillis());
}
public static String blockToString(Block block) {

View File

@@ -42,7 +42,7 @@ public class WorldData implements IWorldData {
this.waypoints = new Waypoints(directory.resolve("waypoints"));
}
void onClose() {
public void onClose() {
Baritone.INSTANCE.getExecutor().execute(() -> {
System.out.println("Started saving the world in a new thread");
cache.save();

View File

@@ -17,6 +17,7 @@
package baritone.cache;
import baritone.api.cache.IWorldScanner;
import baritone.utils.Helper;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
@@ -29,20 +30,12 @@ import net.minecraft.world.chunk.storage.ExtendedBlockStorage;
import java.util.LinkedList;
import java.util.List;
public enum WorldScanner implements Helper {
public enum WorldScanner implements IWorldScanner, Helper {
INSTANCE;
/**
* Scans the world, up to your render distance, for the specified blocks.
*
* @param blocks The blocks to scan for
* @param max The maximum number of blocks to scan before cutoff
* @param yLevelThreshold If a block is found within this Y level, the current result will be
* returned, if the value is negative, then this condition doesn't apply.
* @param maxSearchRadius The maximum chunk search radius
* @return The matching block positions
*/
public List<BlockPos> scanLoadedChunks(List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius) {
@Override
public List<BlockPos> scanChunkRadius(List<Block> blocks, int max, int yLevelThreshold, int maxSearchRadius) {
if (blocks.contains(null)) {
throw new IllegalStateException("Invalid block name should have been caught earlier: " + blocks.toString());
}

View File

@@ -18,16 +18,17 @@
package baritone.pathing.calc;
import baritone.Baritone;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.BetterBlockPos;
import baritone.pathing.calc.openset.BinaryHeapOpenSet;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Moves;
import baritone.pathing.path.IPath;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.pathing.MoveResult;
import net.minecraft.util.math.BlockPos;
import baritone.utils.pathing.BetterWorldBorder;
import baritone.utils.pathing.MutableMoveResult;
import java.util.HashSet;
import java.util.Optional;
@@ -41,14 +42,14 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
private final Optional<HashSet<Long>> favoredPositions;
public AStarPathFinder(BlockPos start, Goal goal, Optional<HashSet<Long>> favoredPositions) {
super(start, goal);
public AStarPathFinder(int startX, int startY, int startZ, Goal goal, Optional<HashSet<Long>> favoredPositions) {
super(startX, startY, startZ, goal);
this.favoredPositions = favoredPositions;
}
@Override
protected Optional<IPath> calculate0(long timeout) {
startNode = getNodeAtPosition(start.x, start.y, start.z);
startNode = getNodeAtPosition(startX, startY, startZ, BetterBlockPos.longHash(startX, startY, startZ));
startNode.cost = 0;
startNode.combinedCost = startNode.estimatedCostToGoal;
BinaryHeapOpenSet openSet = new BinaryHeapOpenSet();
@@ -61,7 +62,9 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
bestSoFar[i] = startNode;
}
CalculationContext calcContext = new CalculationContext();
MutableMoveResult res = new MutableMoveResult();
HashSet<Long> favored = favoredPositions.orElse(null);
BetterWorldBorder worldBorder = new BetterWorldBorder(world().getWorldBorder());
BlockStateInterface.clearCachedChunk();
long startTime = System.nanoTime() / 1000000L;
boolean slowPath = Baritone.settings().slowPath.get();
@@ -105,24 +108,38 @@ public final class AStarPathFinder extends AbstractNodeCostSearch implements Hel
continue;
}
}
MoveResult res = moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z);
if (!moves.dynamicXZ && !worldBorder.entirelyContains(newX, newZ)) {
continue;
}
if (currentNode.y + moves.yOffset > 256 || currentNode.y + moves.yOffset < 0) {
continue;
}
res.reset();
moves.apply(calcContext, currentNode.x, currentNode.y, currentNode.z, res);
numMovementsConsidered++;
double actionCost = res.cost;
if (actionCost >= ActionCosts.COST_INF) {
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.destX != newX || res.destZ != newZ)) {
throw new IllegalStateException(moves + " " + res.destX + " " + newX + " " + res.destZ + " " + newZ);
}
if (actionCost <= 0) {
throw new IllegalStateException(moves + " calculated implausible cost " + actionCost);
}
if (favoring && favored.contains(posHash(res.destX, res.destY, res.destZ))) {
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);
}
if (!moves.dynamicY && res.y != currentNode.y + moves.yOffset) {
throw new IllegalStateException(moves + " " + res.x + " " + newX + " " + res.z + " " + newZ);
}
long hashCode = BetterBlockPos.longHash(res.x, res.y, res.z);
if (favoring && favored.contains(hashCode)) {
// see issue #18
actionCost *= favorCoeff;
}
PathNode neighbor = getNodeAtPosition(res.destX, res.destY, res.destZ);
PathNode neighbor = getNodeAtPosition(res.x, res.y, res.z, hashCode);
double tentativeCost = currentNode.cost + actionCost;
if (tentativeCost < neighbor.cost) {
if (tentativeCost < 0) {

View File

@@ -17,11 +17,11 @@
package baritone.pathing.calc;
import baritone.Baritone;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.calc.IPathFinder;
import baritone.api.pathing.goals.Goal;
import baritone.pathing.path.IPath;
import baritone.utils.pathing.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import net.minecraft.util.math.BlockPos;
import java.util.Optional;
@@ -37,7 +37,9 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
*/
private static AbstractNodeCostSearch currentlyRunning = null;
protected final BetterBlockPos start;
protected final int startX;
protected final int startY;
protected final int startZ;
protected final Goal goal;
@@ -68,10 +70,12 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
*/
protected final static double MIN_DIST_PATH = 5;
AbstractNodeCostSearch(BlockPos start, Goal goal) {
this.start = new BetterBlockPos(start.getX(), start.getY(), start.getZ());
AbstractNodeCostSearch(int startX, int startY, int startZ, Goal goal) {
this.startX = startX;
this.startY = startY;
this.startZ = startZ;
this.goal = goal;
this.map = new Long2ObjectOpenHashMap<>();
this.map = new Long2ObjectOpenHashMap<>(Baritone.settings().pathingMapDefaultSize.value, Baritone.settings().pathingMapLoadFactor.get());
}
public void cancel() {
@@ -85,7 +89,7 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
this.cancelRequested = false;
try {
Optional<IPath> path = calculate0(timeout);
path.ifPresent(IPath::postprocess);
path.ifPresent(IPath::postProcess);
isFinished = true;
return path;
} finally {
@@ -114,22 +118,21 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
* @return The distance, squared
*/
protected double getDistFromStartSq(PathNode n) {
int xDiff = n.x - start.x;
int yDiff = n.y - start.y;
int zDiff = n.z - start.z;
int xDiff = n.x - startX;
int yDiff = n.y - startY;
int zDiff = n.z - startZ;
return xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
}
/**
* Attempts to search the {@link BlockPos} to {@link PathNode} map
* Attempts to search the block position hashCode long to {@link PathNode} map
* for the node mapped to the specified pos. If no node is found,
* a new node is created.
*
* @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 = posHash(x, y, z);
protected PathNode getNodeAtPosition(int x, int y, int z, long hashCode) {
PathNode node = map.get(hashCode);
if (node == null) {
node = new PathNode(x, y, z, goal);
@@ -138,25 +141,6 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
return node;
}
public static long posHash(int x, int y, int z) {
/*
* This is the hashcode implementation of Vec3i, the superclass of BlockPos
*
* public int hashCode() {
* return (this.getY() + this.getZ() * 31) * 31 + this.getX();
* }
*
* That is terrible and has tons of collisions and makes the HashMap terribly inefficient.
*
* That's why we grab out the X, Y, Z and calculate our own hashcode
*/
long hash = 3241;
hash = 3457689L * hash + x;
hash = 8734625L * hash + y;
hash = 2873465L * hash + z;
return hash;
}
public static void forceCancel() {
currentlyRunning = null;
}
@@ -220,12 +204,11 @@ public abstract class AbstractNodeCostSearch implements IPathFinder {
return goal;
}
@Override
public final BlockPos getStart() {
return start;
}
public static Optional<AbstractNodeCostSearch> getCurrentlyRunning() {
return Optional.ofNullable(currentlyRunning);
}
public static AbstractNodeCostSearch currentlyRunning() {
return currentlyRunning;
}
}

View File

@@ -15,11 +15,12 @@
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.pathing.path;
package baritone.pathing.calc;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.pathing.movement.Movement;
import baritone.utils.pathing.BetterBlockPos;
import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos;
import java.util.Collections;
import java.util.List;
@@ -28,13 +29,13 @@ public class CutoffPath implements IPath {
private final List<BetterBlockPos> path;
private final List<Movement> movements;
private final List<IMovement> movements;
private final int numNodes;
private final Goal goal;
public CutoffPath(IPath prev, int lastPositionToInclude) {
CutoffPath(IPath prev, int lastPositionToInclude) {
path = prev.positions().subList(0, lastPositionToInclude + 1);
movements = prev.movements().subList(0, lastPositionToInclude + 1);
numNodes = prev.getNumNodesConsidered();
@@ -47,7 +48,7 @@ public class CutoffPath implements IPath {
}
@Override
public List<Movement> movements() {
public List<IMovement> movements() {
return Collections.unmodifiableList(movements);
}

View File

@@ -17,12 +17,16 @@
package baritone.pathing.calc;
import baritone.api.BaritoneAPI;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.IMovement;
import baritone.api.utils.BetterBlockPos;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.Moves;
import baritone.pathing.path.IPath;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.client.Minecraft;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.ArrayList;
import java.util.Collections;
@@ -86,11 +90,11 @@ class Path implements IPath {
throw new IllegalStateException();
}
PathNode current = end;
LinkedList<BetterBlockPos> tempPath = new LinkedList<>(); // Repeatedly inserting to the beginning of an arraylist is O(n^2)
LinkedList<Movement> tempMovements = new LinkedList<>(); // Instead, do it into a linked list, then convert at the end
LinkedList<BetterBlockPos> tempPath = new LinkedList<>();
// Repeatedly inserting to the beginning of an arraylist is O(n^2)
// Instead, do it into a linked list, then convert at the end
while (!current.equals(start)) {
tempPath.addFirst(new BetterBlockPos(current.x, current.y, current.z));
tempMovements.addFirst(runBackwards(current.previous, current));
current = current.previous;
}
tempPath.addFirst(this.start);
@@ -98,20 +102,6 @@ class Path implements IPath {
// inserting into a LinkedList<E> keeps track of length, then when we addall (which calls .toArray) it's able
// to performantly do that conversion since it knows the length.
path.addAll(tempPath);
movements.addAll(tempMovements);
}
private static Movement runBackwards(PathNode src0, PathNode dest0) { // TODO this is horrifying
BetterBlockPos src = new BetterBlockPos(src0.x, src0.y, src0.z);
BetterBlockPos dest = new BetterBlockPos(dest0.x, dest0.y, dest0.z);
for (Moves moves : Moves.values()) {
Movement move = moves.apply0(src);
if (move.getDest().equals(dest)) {
return move;
}
}
// leave this as IllegalStateException; it's caught in AbstractNodeCostSearch
throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src));
}
/**
@@ -140,19 +130,42 @@ class Path implements IPath {
}
}
private void assembleMovements() {
if (path.isEmpty() || !movements.isEmpty()) {
throw new IllegalStateException();
}
for (int i = 0; i < path.size() - 1; i++) {
movements.add(runBackwards(path.get(i), path.get(i + 1)));
}
}
private static Movement runBackwards(BetterBlockPos src, BetterBlockPos dest) { // TODO this is horrifying
for (Moves moves : Moves.values()) {
Movement move = moves.apply0(src);
if (move.getDest().equals(dest)) {
// TODO instead of recalculating here, could we take pathNode.cost - pathNode.prevNode.cost to get the cost as-calculated?
move.recalculateCost(); // have to calculate the cost at calculation time so we can accurately judge whether a cost increase happened between cached calculation and real execution
return move;
}
}
// this is no longer called from bestPathSoFar, now it's in postprocessing
throw new IllegalStateException("Movement became impossible during calculation " + src + " " + dest + " " + dest.subtract(src));
}
@Override
public void postprocess() {
public void postProcess() {
if (verified) {
throw new IllegalStateException();
}
verified = true;
assembleMovements();
// more post processing here
movements.forEach(Movement::checkLoadedChunk);
sanityCheck();
}
@Override
public List<Movement> movements() {
public List<IMovement> movements() {
if (!verified) {
throw new IllegalStateException();
}
@@ -178,4 +191,28 @@ class Path implements IPath {
public BetterBlockPos getDest() {
return end;
}
@Override
public IPath cutoffAtLoadedChunks() {
for (int i = 0; i < positions().size(); i++) {
BlockPos pos = positions().get(i);
if (Minecraft.getMinecraft().world.getChunk(pos) instanceof EmptyChunk) {
return new CutoffPath(this, i);
}
}
return this;
}
@Override
public IPath staticCutoff(Goal destination) {
if (length() < BaritoneAPI.getSettings().pathCutoffMinimumLength.get()) {
return this;
}
if (destination == null || destination.isInGoal(getDest())) {
return this;
}
double factor = BaritoneAPI.getSettings().pathCutoffFactor.get();
int newLength = (int) (length() * factor);
return new CutoffPath(this, newLength);
}
}

View File

@@ -19,6 +19,7 @@ package baritone.pathing.calc;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.BetterBlockPos;
/**
* A node in the path, containing the cost and steps to get to it.
@@ -30,20 +31,20 @@ public final class PathNode {
/**
* The position of this node
*/
final int x;
final int y;
final int z;
public final int x;
public final int y;
public final int z;
/**
* Cached, should always be equal to goal.heuristic(pos)
*/
final double estimatedCostToGoal;
public final double estimatedCostToGoal;
/**
* Total cost of getting from start to here
* Mutable and changed by PathFinder
*/
double cost;
public double cost;
/**
* Should always be equal to estimatedCosttoGoal + cost
@@ -55,13 +56,13 @@ public final class PathNode {
* In the graph search, what previous node contributed to the cost
* Mutable and changed by PathFinder
*/
PathNode previous;
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.
*/
boolean isOpen;
public boolean isOpen;
/**
* Where is this node in the array flattenization of the binary heap? Needed for decrease-key operations.
@@ -85,7 +86,7 @@ public final class PathNode {
*/
@Override
public int hashCode() {
return (int) AbstractNodeCostSearch.posHash(x, y, z);
return (int) BetterBlockPos.longHash(x, y, z);
}
@Override

View File

@@ -18,8 +18,11 @@
package baritone.pathing.movement;
import baritone.Baritone;
import baritone.api.pathing.movement.ActionCosts;
import baritone.utils.Helper;
import baritone.utils.ToolSet;
import baritone.utils.pathing.BetterWorldBorder;
import net.minecraft.enchantment.EnchantmentHelper;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
@@ -40,6 +43,9 @@ public class CalculationContext implements Helper {
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 CalculationContext() {
this(new ToolSet());
@@ -54,13 +60,46 @@ public class CalculationContext implements Helper {
this.allowBreak = Baritone.settings().allowBreak.get();
this.maxFallHeightNoWater = Baritone.settings().maxFallHeightNoWater.get();
this.maxFallHeightBucket = Baritone.settings().maxFallHeightBucket.get();
int depth = EnchantmentHelper.getDepthStriderModifier(player());
if (depth > 3) {
depth = 3;
}
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();
// 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.
this.worldBorder = new BetterWorldBorder(world().getWorldBorder());
}
public boolean canPlaceThrowawayAt(int x, int y, int z) {
if (!hasThrowaway()) { // only true if allowPlace is true, see constructor
return false;
}
if (isPossiblyProtected(x, y, z)) {
return false;
}
return worldBorder.canPlaceAt(x, z); // TODO perhaps MovementHelper.canPlaceAgainst could also use this?
}
public boolean canBreakAt(int x, int y, int z) {
if (!allowBreak()) {
return false;
}
if (isPossiblyProtected(x, y, z)) {
return false;
}
return true;
}
public boolean isPossiblyProtected(int x, int y, int z) {
// TODO more protection logic here; see #220
return false;
}
public ToolSet getToolSet() {
return this.toolSet;
return toolSet;
}
public boolean hasWaterBucket() {
@@ -91,4 +130,11 @@ public class CalculationContext implements Helper {
return maxFallHeightBucket;
}
public double waterWalkSpeed() {
return waterWalkSpeed;
}
public double breakBlockAdditionalCost() {
return breakBlockAdditionalCost;
}
}

View File

@@ -18,12 +18,17 @@
package baritone.pathing.movement;
import baritone.Baritone;
import baritone.api.pathing.movement.IMovement;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.VecUtils;
import baritone.behavior.LookBehavior;
import baritone.behavior.LookBehaviorUtils;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.BlockBreakHelper;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler;
import net.minecraft.block.BlockLiquid;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
@@ -36,7 +41,7 @@ import java.util.Optional;
import static baritone.utils.InputOverrideHandler.Input;
public abstract class Movement implements Helper, MovementHelper {
public abstract class Movement implements IMovement, Helper, MovementHelper {
protected static final EnumFacing[] HORIZONTALS = {EnumFacing.NORTH, EnumFacing.SOUTH, EnumFacing.EAST, EnumFacing.WEST};
@@ -77,24 +82,27 @@ public abstract class Movement implements Helper, MovementHelper {
this(src, dest, toBreak, null);
}
public double getCost(CalculationContext context) {
@Override
public double getCost() {
if (cost == null) {
cost = calculateCost(context != null ? context : new CalculationContext());
cost = calculateCost(new CalculationContext());
}
return cost;
}
protected abstract double calculateCost(CalculationContext context);
@Override
public double recalculateCost() {
cost = null;
return getCost(null);
return getCost();
}
protected void override(double cost) {
this.cost = cost;
}
@Override
public double calculateCostWithoutCaching() {
return calculateCost(new CalculationContext());
}
@@ -105,12 +113,16 @@ public abstract class Movement implements Helper, MovementHelper {
*
* @return Status
*/
@Override
public MovementStatus update() {
player().capabilities.allowFlying = false;
MovementState latestState = updateState(currentState);
if (BlockStateInterface.isLiquid(playerFeet())) {
latestState.setInput(Input.JUMP, true);
}
if (player().isEntityInsideOpaqueBlock()) {
latestState.setInput(Input.CLICK_LEFT, true);
}
// If the movement target has to force the new rotations, or we aren't using silent move, then force the rotations
latestState.getTarget().getRotation().ifPresent(rotation ->
@@ -147,7 +159,8 @@ public abstract class Movement implements Helper, MovementHelper {
currentState = latestState;
if (isFinished()) {
// If the current status indicates a completed movement
if (currentState.getStatus().isComplete()) {
onFinish(latestState);
}
@@ -162,7 +175,7 @@ public abstract class Movement implements Helper, MovementHelper {
for (BetterBlockPos blockPos : positionsToBreak) {
if (!MovementHelper.canWalkThrough(blockPos) && !(BlockStateInterface.getBlock(blockPos) instanceof BlockLiquid)) { // can't break liquid, so don't try
somethingInTheWay = true;
Optional<Rotation> reachable = LookBehaviorUtils.reachable(blockPos);
Optional<Rotation> reachable = RotationUtils.reachable(player(), blockPos);
if (reachable.isPresent()) {
MovementHelper.switchToBestToolFor(BlockStateInterface.get(blockPos));
state.setTarget(new MovementState.MovementTarget(reachable.get(), true)).setInput(Input.CLICK_LEFT, true);
@@ -172,8 +185,8 @@ public abstract class Movement implements Helper, MovementHelper {
//i'm doing it anyway
//i dont care if theres snow in the way!!!!!!!
//you dont own me!!!!
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(blockPos)), true)
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(player().getPositionEyes(1.0F),
VecUtils.getBlockPosCenter(blockPos)), true)
).setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
return false;
}
@@ -187,16 +200,21 @@ public abstract class Movement implements Helper, MovementHelper {
return true;
}
public boolean isFinished() {
return (currentState.getStatus() != MovementStatus.RUNNING
&& currentState.getStatus() != MovementStatus.PREPPING
&& currentState.getStatus() != MovementStatus.WAITING);
@Override
public boolean safeToCancel() {
return safeToCancel(currentState);
}
protected boolean safeToCancel(MovementState currentState) {
return true;
}
@Override
public BetterBlockPos getSrc() {
return src;
}
@Override
public BetterBlockPos getDest() {
return dest;
}
@@ -215,6 +233,7 @@ public abstract class Movement implements Helper, MovementHelper {
currentState.setStatus(MovementStatus.CANCELED);
}
@Override
public void reset() {
currentState = new MovementState().setStatus(MovementStatus.PREPPING);
}
@@ -239,6 +258,7 @@ public abstract class Movement implements Helper, MovementHelper {
return state;
}
@Override
public BlockPos getDirection() {
return getDest().subtract(getSrc());
}
@@ -247,10 +267,19 @@ public abstract class Movement implements Helper, MovementHelper {
calculatedWhileLoaded = !(world().getChunk(getDest()) instanceof EmptyChunk);
}
@Override
public boolean calculatedWhileLoaded() {
return calculatedWhileLoaded;
}
@Override
public void resetBlockCache() {
toBreakCached = null;
toPlaceCached = null;
toWalkIntoCached = null;
}
@Override
public List<BlockPos> toBreak() {
if (toBreakCached != null) {
return toBreakCached;
@@ -265,6 +294,7 @@ public abstract class Movement implements Helper, MovementHelper {
return result;
}
@Override
public List<BlockPos> toPlace() {
if (toPlaceCached != null) {
return toPlaceCached;
@@ -277,6 +307,7 @@ public abstract class Movement implements Helper, MovementHelper {
return result;
}
@Override
public List<BlockPos> toWalkInto() { // overridden by movementdiagonal
if (toWalkIntoCached == null) {
toWalkIntoCached = new ArrayList<>();

View File

@@ -19,27 +19,25 @@ package baritone.pathing.movement;
import baritone.Baritone;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.Rotation;
import baritone.behavior.LookBehaviorUtils;
import baritone.api.utils.*;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.*;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler;
import baritone.utils.ToolSet;
import net.minecraft.block.*;
import net.minecraft.block.properties.PropertyBool;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.init.Blocks;
import net.minecraft.item.ItemPickaxe;
import net.minecraft.item.ItemStack;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.NonNullList;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.world.chunk.EmptyChunk;
import java.util.Optional;
/**
* Static helpers for cost calculation
*
@@ -47,10 +45,6 @@ import java.util.Optional;
*/
public interface MovementHelper extends ActionCosts, Helper {
static boolean avoidBreaking(BetterBlockPos pos, IBlockState state) {
return avoidBreaking(pos.x, pos.y, pos.z, state);
}
static boolean avoidBreaking(int x, int y, int z, IBlockState state) {
Block b = state.getBlock();
return b == Blocks.ICE // ice becomes water, and water can mess up the path
@@ -73,10 +67,6 @@ public interface MovementHelper extends ActionCosts, Helper {
return canWalkThrough(pos.x, pos.y, pos.z, BlockStateInterface.get(pos));
}
static boolean canWalkThrough(BetterBlockPos pos, IBlockState state) {
return canWalkThrough(pos.x, pos.y, pos.z, state);
}
static boolean canWalkThrough(int x, int y, int z) {
return canWalkThrough(x, y, z, BlockStateInterface.get(x, y, z));
}
@@ -106,7 +96,9 @@ public interface MovementHelper extends ActionCosts, Helper {
return true;
}
if (snow) {
return state.getValue(BlockSnow.LAYERS) < 5; // see BlockSnow.isPassable
// 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 (trapdoor) {
return !state.getValue(BlockTrapDoor.OPEN); // see BlockTrapDoor.isPassable
@@ -138,10 +130,6 @@ public interface MovementHelper extends ActionCosts, Helper {
*
* @return
*/
static boolean fullyPassable(BlockPos pos) {
return fullyPassable(BlockStateInterface.get(pos));
}
static boolean fullyPassable(int x, int y, int z) {
return fullyPassable(BlockStateInterface.get(x, y, z));
}
@@ -169,10 +157,6 @@ public interface MovementHelper extends ActionCosts, Helper {
return block.isPassable(null, null);
}
static boolean isReplacable(BlockPos pos, IBlockState state) {
return isReplacable(pos.getX(), pos.getY(), pos.getZ(), state);
}
static boolean isReplacable(int x, int y, int z, IBlockState state) {
// for MovementTraverse and MovementAscend
// block double plant defaults to true when the block doesn't match, so don't need to check that case
@@ -196,7 +180,7 @@ public interface MovementHelper extends ActionCosts, Helper {
BlockDoublePlant.EnumPlantType kek = state.getValue(BlockDoublePlant.VARIANT);
return kek == BlockDoublePlant.EnumPlantType.FERN || kek == BlockDoublePlant.EnumPlantType.GRASS;
}
return state.getBlock().isReplaceable(null, null);
return state.getMaterial().isReplaceable();
}
static boolean isDoorPassable(BlockPos doorPos, BlockPos playerPos) {
@@ -342,15 +326,6 @@ public interface MovementHelper extends ActionCosts, Helper {
return state.isBlockNormalCube();
}
static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, boolean includeFalling) {
IBlockState state = BlockStateInterface.get(position);
return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling);
}
static double getMiningDurationTicks(CalculationContext context, BetterBlockPos position, IBlockState state, boolean includeFalling) {
return getMiningDurationTicks(context, position.x, position.y, position.z, state, includeFalling);
}
static double getMiningDurationTicks(CalculationContext context, int x, int y, int z, boolean includeFalling) {
return getMiningDurationTicks(context, x, y, z, BlockStateInterface.get(x, y, z), includeFalling);
}
@@ -358,7 +333,7 @@ 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(x, y, z, state)) {
if (!context.allowBreak()) {
if (!context.canBreakAt(x, y, z)) {
return COST_INF;
}
if (avoidBreaking(x, y, z, state)) {
@@ -374,6 +349,7 @@ public interface MovementHelper extends ActionCosts, Helper {
}
double result = m / strVsBlock;
result += context.breakBlockAdditionalCost();
if (includeFalling) {
IBlockState above = BlockStateInterface.get(x, y + 1, z);
if (above.getBlock() instanceof BlockFalling) {
@@ -395,23 +371,11 @@ public interface MovementHelper extends ActionCosts, Helper {
return isBottomSlab(BlockStateInterface.get(pos));
}
/**
* The entity the player is currently looking at
*
* @return the entity object
*/
static Optional<Entity> whatEntityAmILookingAt() {
if (mc.objectMouseOver != null && mc.objectMouseOver.typeOfHit == RayTraceResult.Type.ENTITY) {
return Optional.of(mc.objectMouseOver.entityHit);
}
return Optional.empty();
}
/**
* AutoTool
*/
static void switchToBestTool() {
LookBehaviorUtils.getSelectedBlock().ifPresent(pos -> {
RayTraceUtils.getSelectedBlock().ifPresent(pos -> {
IBlockState state = BlockStateInterface.get(pos);
if (state.getBlock().equals(Blocks.AIR)) {
return;
@@ -456,13 +420,29 @@ public interface MovementHelper extends ActionCosts, Helper {
return true;
}
}
if (Baritone.settings().acceptableThrowawayItems.get().contains(p.inventory.offHandInventory.get(0).getItem())) {
// main hand takes precedence over off hand
// that means that if we have block A selected in main hand and block B in off hand, right clicking places block B
// we've already checked above ^ and the main hand can't possible have an acceptablethrowawayitem
// so we need to select in the main hand something that doesn't right click
// so not a shovel, not a hoe, not a block, etc
for (byte i = 0; i < 9; i++) {
ItemStack item = inv.get(i);
if (item.isEmpty() || item.getItem() instanceof ItemPickaxe) {
if (select) {
p.inventory.currentItem = i;
}
return true;
}
}
}
return false;
}
static void moveTowards(MovementState state, BlockPos pos) {
state.setTarget(new MovementTarget(
new Rotation(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(pos),
new Rotation(RotationUtils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
VecUtils.getBlockPosCenter(pos),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)).getYaw(), mc.player.rotationPitch),
false
)).setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);

View File

@@ -17,6 +17,7 @@
package baritone.pathing.movement;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.Rotation;
import baritone.utils.InputOverrideHandler.Input;
import net.minecraft.util.math.Vec3d;
@@ -72,10 +73,6 @@ public class MovementState {
return this.inputState;
}
public enum MovementStatus {
PREPPING, WAITING, RUNNING, SUCCESS, UNREACHABLE, FAILED, CANCELED
}
public static class MovementTarget {
/**
@@ -87,9 +84,6 @@ public class MovementState {
/**
* Yaw and pitch angles that must be matched
* <p>
* getFirst() -> YAW
* getSecond() -> PITCH
*/
public Rotation rotation;

View File

@@ -17,9 +17,9 @@
package baritone.pathing.movement;
import baritone.api.utils.BetterBlockPos;
import baritone.pathing.movement.movements.*;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.pathing.MoveResult;
import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.util.EnumFacing;
/**
@@ -28,306 +28,326 @@ import net.minecraft.util.EnumFacing;
* @author leijurv
*/
public enum Moves {
DOWNWARD(0, 0) {
DOWNWARD(0, -1, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementDownward(src, src.down());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y - 1, z, MovementDownward.cost(context, x, y, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementDownward.cost(context, x, y, z);
}
},
PILLAR(0, 0) {
PILLAR(0, +1, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementPillar(src, src.up());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y + 1, z, MovementPillar.cost(context, x, y, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementPillar.cost(context, x, y, z);
}
},
TRAVERSE_NORTH(0, -1) {
TRAVERSE_NORTH(0, 0, -1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementTraverse(src, src.north());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y, z - 1, MovementTraverse.cost(context, x, y, z, x, z - 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementTraverse.cost(context, x, y, z, x, z - 1);
}
},
TRAVERSE_SOUTH(0, +1) {
TRAVERSE_SOUTH(0, 0, +1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementTraverse(src, src.south());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y, z + 1, MovementTraverse.cost(context, x, y, z, x, z + 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementTraverse.cost(context, x, y, z, x, z + 1);
}
},
TRAVERSE_EAST(+1, 0) {
TRAVERSE_EAST(+1, 0, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementTraverse(src, src.east());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x + 1, y, z, MovementTraverse.cost(context, x, y, z, x + 1, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementTraverse.cost(context, x, y, z, x + 1, z);
}
},
TRAVERSE_WEST(-1, 0) {
TRAVERSE_WEST(-1, 0, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementTraverse(src, src.west());
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x - 1, y, z, MovementTraverse.cost(context, x, y, z, x - 1, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementTraverse.cost(context, x, y, z, x - 1, z);
}
},
ASCEND_NORTH(0, -1) {
ASCEND_NORTH(0, +1, -1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z - 1));
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y + 1, z - 1, MovementAscend.cost(context, x, y, z, x, z - 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementAscend.cost(context, x, y, z, x, z - 1);
}
},
ASCEND_SOUTH(0, +1) {
ASCEND_SOUTH(0, +1, +1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementAscend(src, new BetterBlockPos(src.x, src.y + 1, src.z + 1));
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x, y + 1, z + 1, MovementAscend.cost(context, x, y, z, x, z + 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementAscend.cost(context, x, y, z, x, z + 1);
}
},
ASCEND_EAST(+1, 0) {
ASCEND_EAST(+1, +1, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementAscend(src, new BetterBlockPos(src.x + 1, src.y + 1, src.z));
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x + 1, y + 1, z, MovementAscend.cost(context, x, y, z, x + 1, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementAscend.cost(context, x, y, z, x + 1, z);
}
},
ASCEND_WEST(-1, 0) {
ASCEND_WEST(-1, +1, 0) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementAscend(src, new BetterBlockPos(src.x - 1, src.y + 1, src.z));
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x - 1, y + 1, z, MovementAscend.cost(context, x, y, z, x - 1, z));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementAscend.cost(context, x, y, z, x - 1, z);
}
},
DESCEND_EAST(+1, 0) {
DESCEND_EAST(+1, -1, 0, false, true) {
@Override
public Movement apply0(BetterBlockPos src) {
MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
if (res.destY == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
MutableMoveResult res = new MutableMoveResult();
apply(new CalculationContext(), src.x, src.y, src.z, res);
if (res.y == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z));
} else {
return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
return new MovementFall(src, new BetterBlockPos(res.x, res.y, res.z));
}
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementDescend.cost(context, x, y, z, x + 1, z);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementDescend.cost(context, x, y, z, x + 1, z, result);
}
},
DESCEND_WEST(-1, 0) {
DESCEND_WEST(-1, -1, 0, false, true) {
@Override
public Movement apply0(BetterBlockPos src) {
MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
if (res.destY == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
MutableMoveResult res = new MutableMoveResult();
apply(new CalculationContext(), src.x, src.y, src.z, res);
if (res.y == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z));
} else {
return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
return new MovementFall(src, new BetterBlockPos(res.x, res.y, res.z));
}
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementDescend.cost(context, x, y, z, x - 1, z);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementDescend.cost(context, x, y, z, x - 1, z, result);
}
},
DESCEND_NORTH(0, -1) {
DESCEND_NORTH(0, -1, -1, false, true) {
@Override
public Movement apply0(BetterBlockPos src) {
MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
if (res.destY == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
MutableMoveResult res = new MutableMoveResult();
apply(new CalculationContext(), src.x, src.y, src.z, res);
if (res.y == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z));
} else {
return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
return new MovementFall(src, new BetterBlockPos(res.x, res.y, res.z));
}
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementDescend.cost(context, x, y, z, x, z - 1);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementDescend.cost(context, x, y, z, x, z - 1, result);
}
},
DESCEND_SOUTH(0, +1) {
DESCEND_SOUTH(0, -1, +1, false, true) {
@Override
public Movement apply0(BetterBlockPos src) {
MoveResult res = apply(new CalculationContext(), src.x, src.y, src.z);
if (res.destY == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
MutableMoveResult res = new MutableMoveResult();
apply(new CalculationContext(), src.x, src.y, src.z, res);
if (res.y == src.y - 1) {
return new MovementDescend(src, new BetterBlockPos(res.x, res.y, res.z));
} else {
return new MovementFall(src, new BetterBlockPos(res.destX, res.destY, res.destZ));
return new MovementFall(src, new BetterBlockPos(res.x, res.y, res.z));
}
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementDescend.cost(context, x, y, z, x, z + 1);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementDescend.cost(context, x, y, z, x, z + 1, result);
}
},
DIAGONAL_NORTHEAST(+1, -1) {
DIAGONAL_NORTHEAST(+1, 0, -1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.EAST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x + 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x + 1, z - 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementDiagonal.cost(context, x, y, z, x + 1, z - 1);
}
},
DIAGONAL_NORTHWEST(-1, -1) {
DIAGONAL_NORTHWEST(-1, 0, -1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementDiagonal(src, EnumFacing.NORTH, EnumFacing.WEST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x - 1, y, z - 1, MovementDiagonal.cost(context, x, y, z, x - 1, z - 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementDiagonal.cost(context, x, y, z, x - 1, z - 1);
}
},
DIAGONAL_SOUTHEAST(+1, +1) {
DIAGONAL_SOUTHEAST(+1, 0, +1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.EAST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x + 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x + 1, z + 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementDiagonal.cost(context, x, y, z, x + 1, z + 1);
}
},
DIAGONAL_SOUTHWEST(-1, +1) {
DIAGONAL_SOUTHWEST(-1, 0, +1) {
@Override
public Movement apply0(BetterBlockPos src) {
return new MovementDiagonal(src, EnumFacing.SOUTH, EnumFacing.WEST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return new MoveResult(x - 1, y, z + 1, MovementDiagonal.cost(context, x, y, z, x - 1, z + 1));
public double cost(CalculationContext context, int x, int y, int z) {
return MovementDiagonal.cost(context, x, y, z, x - 1, z + 1);
}
},
PARKOUR_NORTH(0, -4, true) {
PARKOUR_NORTH(0, 0, -4, true, false) {
@Override
public Movement apply0(BetterBlockPos src) {
return MovementParkour.cost(new CalculationContext(), src, EnumFacing.NORTH);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementParkour.cost(context, x, y, z, EnumFacing.NORTH);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementParkour.cost(context, x, y, z, EnumFacing.NORTH, result);
}
},
PARKOUR_SOUTH(0, +4, true) {
PARKOUR_SOUTH(0, 0, +4, true, false) {
@Override
public Movement apply0(BetterBlockPos src) {
return MovementParkour.cost(new CalculationContext(), src, EnumFacing.SOUTH);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementParkour.cost(context, x, y, z, EnumFacing.SOUTH);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementParkour.cost(context, x, y, z, EnumFacing.SOUTH, result);
}
},
PARKOUR_EAST(+4, 0, true) {
PARKOUR_EAST(+4, 0, 0, true, false) {
@Override
public Movement apply0(BetterBlockPos src) {
return MovementParkour.cost(new CalculationContext(), src, EnumFacing.EAST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementParkour.cost(context, x, y, z, EnumFacing.EAST);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementParkour.cost(context, x, y, z, EnumFacing.EAST, result);
}
},
PARKOUR_WEST(-4, 0, true) {
PARKOUR_WEST(-4, 0, 0, true, false) {
@Override
public Movement apply0(BetterBlockPos src) {
return MovementParkour.cost(new CalculationContext(), src, EnumFacing.WEST);
}
@Override
public MoveResult apply(CalculationContext context, int x, int y, int z) {
return MovementParkour.cost(context, x, y, z, EnumFacing.WEST);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
MovementParkour.cost(context, x, y, z, EnumFacing.WEST, result);
}
};
public final boolean dynamicXZ;
public final boolean dynamicY;
public final int xOffset;
public final int yOffset;
public final int zOffset;
Moves(int x, int z, boolean dynamicXZ) {
Moves(int x, int y, int z, boolean dynamicXZ, boolean dynamicY) {
this.xOffset = x;
this.yOffset = y;
this.zOffset = z;
this.dynamicXZ = dynamicXZ;
this.dynamicY = dynamicY;
}
Moves(int x, int z) {
this(x, z, false);
Moves(int x, int y, int z) {
this(x, y, z, false, false);
}
public abstract Movement apply0(BetterBlockPos src);
public abstract MoveResult apply(CalculationContext context, int x, int y, int z);
public void apply(CalculationContext context, int x, int y, int z, MutableMoveResult result) {
if (dynamicXZ || dynamicY) {
throw new UnsupportedOperationException();
}
result.x = x + xOffset;
result.y = y + yOffset;
result.z = z + zOffset;
result.cost = cost(context, x, y, z);
}
public double cost(CalculationContext context, int x, int y, int z) {
throw new UnsupportedOperationException();
}
}

View File

@@ -18,16 +18,16 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.behavior.LookBehaviorUtils;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RayTraceUtils;
import baritone.api.utils.RotationUtils;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -71,8 +71,8 @@ public class MovementAscend extends Movement {
return COST_INF;// the only thing we can ascend onto from a bottom slab is another bottom slab
}
boolean hasToPlace = false;
if (!MovementHelper.canWalkOn(destX, y, z, toPlace)) {
if (!context.hasThrowaway()) {
if (!MovementHelper.canWalkOn(destX, y, destZ, toPlace)) {
if (!context.canPlaceThrowawayAt(destX, y, destZ)) {
return COST_INF;
}
if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y, destZ, toPlace)) {
@@ -101,14 +101,15 @@ public class MovementAscend extends Movement {
// 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
if (!(BlockStateInterface.getBlock(x, y + 1, z) instanceof BlockFalling) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling)) {
// if both of those are BlockFalling, that means that by standing on src
if (MovementHelper.canWalkThrough(x, y + 1, z) || !((srcUp2 = BlockStateInterface.get(x, y + 2, z)).getBlock() instanceof BlockFalling)) {
// if the lower one is can't walk through and the upper one is falling, that means that by standing on src
// (the presupposition of this Movement)
// we have necessarily already cleared the entire BlockFalling stack
// on top of our head
// but if either of them aren't BlockFalling, that means we're still in suffocation danger
// so don't do it
// as in, if we have a block, then two BlockFallings on top of it
// and that block is x, y+1, z, and we'd have to clear it to even start this movement
// we don't need to worry about those BlockFallings because we've already cleared them
return COST_INF;
}
// you may think we only need to check srcUp2, not srcUp
@@ -180,10 +181,10 @@ public class MovementAscend extends Movement {
double faceX = (dest.getX() + anAgainst.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + anAgainst.getY()) * 0.5D;
double faceZ = (dest.getZ() + anAgainst.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
RayTraceUtils.getSelectedBlock().ifPresent(selectedBlock -> {
if (Objects.equals(selectedBlock, anAgainst) && selectedBlock.offset(side).equals(positionToPlace)) {
ticksWithoutPlacement++;
state.setInput(InputOverrideHandler.Input.SNEAK, true);
@@ -197,7 +198,7 @@ public class MovementAscend extends Movement {
} else {
state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true); // break whatever replaceable block is in the way
}
System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
//System.out.println("Trying to look at " + anAgainst + ", actually looking at" + selectedBlock);
});
return state;
}

View File

@@ -18,23 +18,21 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.pathing.MoveResult;
import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.block.Block;
import net.minecraft.block.BlockFalling;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import net.minecraft.util.math.BlockPos;
import static baritone.utils.pathing.MoveResult.IMPOSSIBLE;
public class MovementDescend extends Movement {
private int numTicks = 0;
@@ -51,31 +49,33 @@ public class MovementDescend extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
MoveResult result = cost(context, src.x, src.y, src.z, dest.x, dest.z);
if (result.destY != dest.y) {
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 a fall not a descend
}
return result.cost;
}
public static MoveResult cost(CalculationContext context, int x, int y, int z, int destX, int destZ) {
public static void cost(CalculationContext context, int x, int y, int z, int destX, int destZ, MutableMoveResult res) {
Block fromDown = BlockStateInterface.get(x, y - 1, z).getBlock();
if (fromDown == Blocks.LADDER || fromDown == Blocks.VINE) {
return IMPOSSIBLE;
return;
}
double totalCost = 0;
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, false);
IBlockState destDown = BlockStateInterface.get(destX, y - 1, destZ);
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y - 1, destZ, destDown, false);
if (totalCost >= COST_INF) {
return IMPOSSIBLE;
return;
}
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y, destZ, false);
if (totalCost >= COST_INF) {
return IMPOSSIBLE;
return;
}
totalCost += MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, true); // only the top block in the 3 we need to mine needs to consider the falling blocks above
if (totalCost >= COST_INF) {
return IMPOSSIBLE;
return;
}
// A
@@ -90,12 +90,12 @@ public class MovementDescend extends Movement {
IBlockState below = BlockStateInterface.get(destX, y - 2, destZ);
if (!MovementHelper.canWalkOn(destX, y - 2, destZ, below)) {
return dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below);
dynamicFallCost(context, x, y, z, destX, destZ, totalCost, below, res);
return;
}
Block tmp1 = BlockStateInterface.get(destX, y - 1, destZ).getBlock();
if (tmp1 == Blocks.LADDER || tmp1 == Blocks.VINE) {
return IMPOSSIBLE;
if (destDown.getBlock() == Blocks.LADDER || destDown.getBlock() == Blocks.VINE) {
return;
}
// we walk half the block plus 0.3 to get to the edge, then we walk the other 0.2 while simultaneously falling (math.max because of how it's in parallel)
@@ -105,55 +105,72 @@ public class MovementDescend extends Movement {
walk = WALK_ONE_OVER_SOUL_SAND_COST;
}
totalCost += walk + Math.max(FALL_N_BLOCKS_COST[1], CENTER_AFTER_FALL_COST);
return new MoveResult(destX, y - 1, destZ, totalCost);
res.x = destX;
res.y = y - 1;
res.z = destZ;
res.cost = totalCost;
}
public static MoveResult dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below) {
public static void dynamicFallCost(CalculationContext context, int x, int y, int z, int destX, int destZ, double frontBreak, IBlockState below, MutableMoveResult res) {
if (frontBreak != 0 && BlockStateInterface.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 IMPOSSIBLE;
return;
}
if (!MovementHelper.canWalkThrough(destX, y - 2, destZ, below) && below.getBlock() != Blocks.WATER) {
return IMPOSSIBLE;
return;
}
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 IMPOSSIBLE;
return;
}
IBlockState ontoBlock = BlockStateInterface.get(destX, newY, destZ);
double tentativeCost = WALK_OFF_BLOCK_COST + FALL_N_BLOCKS_COST[fallHeight] + frontBreak;
if (ontoBlock.getBlock() == Blocks.WATER && !BlockStateInterface.isFlowing(ontoBlock)) { // TODO flowing check required here?
if (ontoBlock.getBlock() == Blocks.WATER && !BlockStateInterface.isFlowing(ontoBlock) && BlockStateInterface.getBlock(destX, newY + 1, destZ) != Blocks.WATERLILY) { // TODO flowing check required here?
// 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 IMPOSSIBLE; // TODO fix
return; // TODO fix
}
// found a fall into water
return new MoveResult(destX, newY, destZ, tentativeCost); // TODO incorporate water swim up cost?
res.x = destX;
res.y = newY;
res.z = destZ;
res.cost = tentativeCost;// TODO incorporate water swim up cost?
return;
}
if (ontoBlock.getBlock() == Blocks.FLOWING_WATER) {
return IMPOSSIBLE;
return;
}
if (MovementHelper.canWalkThrough(destX, newY, destZ, ontoBlock)) {
continue;
}
if (!MovementHelper.canWalkOn(destX, newY, destZ, ontoBlock)) {
return IMPOSSIBLE;
return;
}
if (MovementHelper.isBottomSlab(ontoBlock)) {
return IMPOSSIBLE; // falling onto a half slab is really glitchy, and can cause more fall damage than we'd expect
return; // 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) {
return new MoveResult(destX, newY + 1, destZ, tentativeCost + context.placeBlockCost()); // this is the block we're falling onto, so dest is +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;
}
if (fallHeight <= context.maxFallHeightNoWater() + 1) {
// fallHeight = 4 means onto.up() is 3 blocks down, which is the max
return new MoveResult(destX, newY + 1, destZ, tentativeCost);
res.x = destX;
res.y = newY + 1;
res.z = destZ;
res.cost = tentativeCost;
return;
} else {
return IMPOSSIBLE;
return;
}
}
}
@@ -170,9 +187,9 @@ public class MovementDescend extends Movement {
if (BlockStateInterface.isLiquid(dest) || player().posY - playerFeet.getY() < 0.094) { // lilypads
// Wait until we're actually on the ground before saying we're done because sometimes we continue to fall if the next action starts immediately
return state.setStatus(MovementStatus.SUCCESS);
} else {
System.out.println(player().posY + " " + playerFeet.getY() + " " + (player().posY - playerFeet.getY()));
}
}/* else {
// System.out.println(player().posY + " " + playerFeet.getY() + " " + (player().posY - playerFeet.getY()));
}*/
}
double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = player().posZ - (dest.getZ() + 0.5);

View File

@@ -17,13 +17,14 @@
package baritone.pathing.movement.movements;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
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.InputOverrideHandler;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@@ -85,37 +86,54 @@ public class MovementDiagonal extends Movement {
return COST_INF;
}
IBlockState pb0 = BlockStateInterface.get(x, y, destZ);
IBlockState pb1 = BlockStateInterface.get(x, y + 1, destZ);
IBlockState pb2 = BlockStateInterface.get(destX, y, z);
IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z);
double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false) + MovementHelper.getMiningDurationTicks(context, x, y + 1, destZ, pb1, true);
double optionB = MovementHelper.getMiningDurationTicks(context, destX, y, z, pb2, false) + MovementHelper.getMiningDurationTicks(context, destX, y + 1, z, pb3, true);
double optionA = MovementHelper.getMiningDurationTicks(context, x, y, destZ, pb0, false);
double optionB = MovementHelper.getMiningDurationTicks(context, destX, y, z, pb2, false);
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;
}
IBlockState pb1 = BlockStateInterface.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;
}
IBlockState pb3 = BlockStateInterface.get(destX, y + 1, z);
if (optionA == 0) {
if (MovementHelper.avoidWalkingInto(pb2.getBlock()) || MovementHelper.avoidWalkingInto(pb3.getBlock())) {
// at this point we're done calculating optionA, so we can check if it's actually possible to edge around in that direction
if ((MovementHelper.avoidWalkingInto(pb2.getBlock()) && pb2.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb3.getBlock()) && pb3.getBlock() != Blocks.WATER)) {
return COST_INF;
}
}
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;
}
if (optionB == 0) {
if (MovementHelper.avoidWalkingInto(pb0.getBlock()) || MovementHelper.avoidWalkingInto(pb1.getBlock())) {
// and now that option B is fully calculated, see if we can edge around that way
if ((MovementHelper.avoidWalkingInto(pb0.getBlock()) && pb0.getBlock() != Blocks.WATER) || (MovementHelper.avoidWalkingInto(pb1.getBlock()) && pb1.getBlock() != Blocks.WATER)) {
return COST_INF;
}
}
boolean water = false;
if (BlockStateInterface.isWater(BlockStateInterface.getBlock(x, y, z)) || BlockStateInterface.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 = WALK_ONE_IN_WATER_COST;
multiplier = context.waterWalkSpeed();
water = true;
}
if (optionA != 0 || optionB != 0) {
multiplier *= SQRT_2 - 0.001; // TODO tune
}
if (multiplier == WALK_ONE_BLOCK_COST && context.canSprint()) {
// If we aren't edging around anything, and we aren't in water or soul sand
if (context.canSprint() && !water) {
// If we aren't edging around anything, and we aren't in water
// We can sprint =D
multiplier = SPRINT_ONE_BLOCK_COST;
// Don't check for soul sand, since we can sprint on that too
multiplier *= SPRINT_MULTIPLIER;
}
return multiplier * SQRT_2;
}
@@ -123,12 +141,12 @@ public class MovementDiagonal extends Movement {
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING) {
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
if (playerFeet().equals(dest)) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
state.setStatus(MovementStatus.SUCCESS);
return state;
}
if (!BlockStateInterface.isLiquid(playerFeet())) {

View File

@@ -17,12 +17,13 @@
package baritone.pathing.movement.movements;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
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.BetterBlockPos;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
@@ -64,12 +65,12 @@ public class MovementDownward extends Movement {
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING) {
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
if (playerFeet().equals(dest)) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
return state.setStatus(MovementStatus.SUCCESS);
}
double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = player().posZ - (dest.getZ() + 0.5);

View File

@@ -18,19 +18,16 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.pathing.movement.MovementState.MovementStatus;
import baritone.pathing.movement.MovementState.MovementTarget;
import baritone.utils.BlockStateInterface;
import baritone.utils.InputOverrideHandler;
import baritone.utils.RayTraceUtils;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.pathing.MoveResult;
import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.init.Items;
import net.minecraft.item.ItemStack;
@@ -49,8 +46,9 @@ public class MovementFall extends Movement {
@Override
protected double calculateCost(CalculationContext context) {
MoveResult result = MovementDescend.cost(context, src.x, src.y, src.z, dest.x, dest.z);
if (result.destY != dest.y) {
MutableMoveResult result = new MutableMoveResult();
MovementDescend.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 a descend not a fall
}
return result.cost;
@@ -84,7 +82,7 @@ public class MovementFall extends Movement {
if (targetRotation != null) {
state.setTarget(new MovementTarget(targetRotation, true));
} else {
state.setTarget(new MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.getBlockPosCenter(dest)), false));
state.setTarget(new MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.getBlockPosCenter(dest)), false));
}
if (playerFeet.equals(dest) && (player().posY - playerFeet.getY() < 0.094 || BlockStateInterface.isWater(dest))) { // 0.094 because lilypads
if (BlockStateInterface.isWater(dest)) {
@@ -104,13 +102,20 @@ public class MovementFall extends Movement {
return state.setStatus(MovementStatus.SUCCESS);
}
}
Vec3d destCenter = Utils.getBlockPosCenter(dest); // we are moving to the 0.5 center not the edge (like if we were falling on a ladder)
if (Math.abs(player().posX - destCenter.x) > 0.2 || Math.abs(player().posZ - destCenter.z) > 0.2) {
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(player().posX - destCenter.x) > 0.15 || Math.abs(player().posZ - destCenter.z) > 0.15) {
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
}
return state;
}
@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
// then it's safe to cancel this
return playerFeet().equals(src) || state.getStatus() != MovementStatus.RUNNING;
}
private static BetterBlockPos[] buildPositionsToBreak(BetterBlockPos src, BetterBlockPos dest) {
BetterBlockPos[] toBreak;
int diffX = src.getX() - dest.getX();

View File

@@ -18,27 +18,30 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.behavior.LookBehaviorUtils;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.RayTraceUtils;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.MovementState;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.InputOverrideHandler;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.pathing.MoveResult;
import baritone.utils.pathing.MutableMoveResult;
import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
import java.util.Objects;
import static baritone.utils.pathing.MoveResult.IMPOSSIBLE;
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};
@@ -48,72 +51,81 @@ public class MovementParkour extends Movement {
private final int dist;
private MovementParkour(BetterBlockPos src, int dist, EnumFacing dir) {
super(src, src.offset(dir, dist), EMPTY);
super(src, src.offset(dir, dist), EMPTY, src.offset(dir, dist).down());
this.direction = dir;
this.dist = dist;
}
public static MovementParkour cost(CalculationContext context, BetterBlockPos src, EnumFacing direction) {
MoveResult res = cost(context, src.x, src.y, src.z, direction);
int dist = Math.abs(res.destX - src.x) + Math.abs(res.destZ - src.z);
MutableMoveResult res = new MutableMoveResult();
cost(context, src.x, src.y, src.z, direction, res);
int dist = Math.abs(res.x - src.x) + Math.abs(res.z - src.z);
return new MovementParkour(src, dist, direction);
}
public static MoveResult cost(CalculationContext context, int x, int y, int z, EnumFacing dir) {
public static void cost(CalculationContext context, int x, int y, int z, EnumFacing dir, MutableMoveResult res) {
if (!Baritone.settings().allowParkour.get()) {
return IMPOSSIBLE;
return;
}
IBlockState standingOn = BlockStateInterface.get(x, y - 1, z);
if (standingOn.getBlock() == Blocks.VINE || standingOn.getBlock() == Blocks.LADDER || MovementHelper.isBottomSlab(standingOn)) {
return IMPOSSIBLE;
return;
}
int xDiff = dir.getXOffset();
int zDiff = dir.getZOffset();
IBlockState adj = BlockStateInterface.get(x + xDiff, y - 1, z + zDiff);
if (MovementHelper.avoidWalkingInto(adj.getBlock()) && adj.getBlock() != Blocks.WATER && adj.getBlock() != Blocks.FLOWING_WATER) { // magma sucks
return IMPOSSIBLE;
return;
}
if (MovementHelper.canWalkOn(x + xDiff, y - 1, z + zDiff, adj)) { // don't parkour if we could just traverse (for now)
return IMPOSSIBLE;
return;
}
if (!MovementHelper.fullyPassable(x + xDiff, y, z + zDiff)) {
return IMPOSSIBLE;
return;
}
if (!MovementHelper.fullyPassable(x + xDiff, y + 1, z + zDiff)) {
return IMPOSSIBLE;
return;
}
if (!MovementHelper.fullyPassable(x + xDiff, y + 2, z + zDiff)) {
return IMPOSSIBLE;
return;
}
if (!MovementHelper.fullyPassable(x, y + 2, z)) {
return IMPOSSIBLE;
return;
}
for (int i = 2; i <= (context.canSprint() ? 4 : 3); i++) {
// TODO perhaps dest.up(3) doesn't need to be fullyPassable, just canWalkThrough, possibly?
for (int y2 = 0; y2 < 4; y2++) {
if (!MovementHelper.fullyPassable(x + xDiff * i, y + y2, z + zDiff * i)) {
return IMPOSSIBLE;
return;
}
}
if (MovementHelper.canWalkOn(x + xDiff * i, y - 1, z + zDiff * i)) {
return new MoveResult(x + xDiff * i, y, z + zDiff * i, costFromJumpDistance(i));
res.x = x + xDiff * i;
res.y = y;
res.z = z + zDiff * i;
res.cost = costFromJumpDistance(i);
return;
}
}
if (!context.canSprint()) {
return IMPOSSIBLE;
return;
}
if (!Baritone.settings().allowParkourPlace.get()) {
return IMPOSSIBLE;
return;
}
if (!Baritone.settings().allowPlace.get()) {
Helper.HELPER.logDirect("allowParkourPlace enabled but allowPlace disabled?");
return;
}
int destX = x + 4 * xDiff;
int destZ = z + 4 * zDiff;
IBlockState toPlace = BlockStateInterface.get(destX, y - 1, destZ);
if (!context.hasThrowaway()) {
return IMPOSSIBLE;
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
return;
}
if (toPlace.getBlock() != Blocks.AIR && !BlockStateInterface.isWater(toPlace.getBlock()) && !MovementHelper.isReplacable(destX, y - 1, destZ, toPlace)) {
return IMPOSSIBLE;
return;
}
for (int i = 0; i < 5; i++) {
int againstX = destX + HORIZONTALS_BUT_ALSO_DOWN____SO_EVERY_DIRECTION_EXCEPT_UP[i].getXOffset();
@@ -122,10 +134,13 @@ public class MovementParkour extends Movement {
continue;
}
if (MovementHelper.canPlaceAgainst(againstX, y - 1, againstZ)) {
return new MoveResult(destX, y, destZ, costFromJumpDistance(i) + context.placeBlockCost());
res.x = destX;
res.y = y;
res.z = destZ;
res.cost = costFromJumpDistance(4) + context.placeBlockCost();
return;
}
}
return IMPOSSIBLE;
}
private static double costFromJumpDistance(int dist) {
@@ -137,24 +152,37 @@ public class MovementParkour extends Movement {
case 4:
return SPRINT_ONE_BLOCK_COST * 4;
default:
throw new IllegalStateException("LOL");
throw new IllegalStateException("LOL " + dist);
}
}
@Override
protected double calculateCost(CalculationContext context) {
MoveResult res = cost(context, src.x, src.y, src.z, direction);
if (res.destX != dest.x || res.destZ != dest.z) {
MutableMoveResult res = new MutableMoveResult();
cost(context, src.x, src.y, src.z, direction, res);
if (res.x != dest.x || res.z != dest.z) {
return COST_INF;
}
return res.cost;
}
@Override
public boolean safeToCancel(MovementState state) {
// once this movement is instantiated, the state is default to PREPPING
// but once it's ticked for the first time it changes to RUNNING
// since we don't really know anything about momentum, it suffices to say Parkour can only be canceled on the 0th tick
return state.getStatus() != MovementStatus.RUNNING;
}
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING) {
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
if (player().isHandActive()) {
logDebug("Pausing parkour since hand is active");
return state;
}
if (dist >= 4) {
@@ -162,8 +190,14 @@ public class MovementParkour extends Movement {
}
MovementHelper.moveTowards(state, dest);
if (playerFeet().equals(dest)) {
if (player().posY - playerFeet().getY() < 0.01) {
state.setStatus(MovementState.MovementStatus.SUCCESS);
Block d = BlockStateInterface.getBlock(dest);
if (d == Blocks.VINE || d == Blocks.LADDER) {
// it physically hurt me to add support for parkour jumping onto a vine
// but i did it anyway
return state.setStatus(MovementStatus.SUCCESS);
}
if (player().posY - playerFeet().getY() < 0.094) { // lilypads
state.setStatus(MovementStatus.SUCCESS);
}
} else if (!playerFeet().equals(src)) {
if (playerFeet().equals(src.offset(direction)) || player().posY - playerFeet().getY() > 0.0001) {
@@ -177,15 +211,18 @@ public class MovementParkour extends Movement {
}
if (MovementHelper.canPlaceAgainst(against1)) {
if (!MovementHelper.throwaway(true)) {//get ready to place a throwaway block
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state.setStatus(MovementStatus.UNREACHABLE);
}
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + against1.getY()) * 0.5D;
double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
LookBehaviorUtils.getSelectedBlock().ifPresent(selectedBlock -> {
Rotation place = RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations());
RayTraceResult res = RayTraceUtils.rayTraceTowards(place);
if (res != null && res.typeOfHit == RayTraceResult.Type.BLOCK && res.getBlockPos().equals(against1) && res.getBlockPos().offset(res.sideHit).equals(dest.down())) {
state.setTarget(new MovementState.MovementTarget(place, true));
}
RayTraceUtils.getSelectedBlock().ifPresent(selectedBlock -> {
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(selectedBlock, against1) && selectedBlock.offset(side).equals(dest.down())) {
state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
@@ -193,9 +230,17 @@ public class MovementParkour extends Movement {
}
}
}
if (dist == 3) { // this is a 2 block gap, dest = src + direction * 3
double xDiff = (src.x + 0.5) - player().posX;
double zDiff = (src.z + 0.5) - player().posZ;
double distFromStart = Math.max(Math.abs(xDiff), Math.abs(zDiff));
if (distFromStart < 0.7) {
return state;
}
}
state.setInput(InputOverrideHandler.Input.JUMP, true);
} else {
} else if (!playerFeet().equals(dest.offset(direction, -1))) {
state.setInput(InputOverrideHandler.Input.SPRINT, false);
if (playerFeet().equals(src.offset(direction, -1))) {
MovementHelper.moveTowards(state, src);

View File

@@ -17,15 +17,17 @@
package baritone.pathing.movement.movements;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.Rotation;
import baritone.api.utils.RotationUtils;
import baritone.api.utils.VecUtils;
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.InputOverrideHandler;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -34,18 +36,11 @@ import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Vec3d;
public class MovementPillar extends Movement {
private int numTicks = 0;
public MovementPillar(BetterBlockPos start, BetterBlockPos end) {
super(start, end, new BetterBlockPos[]{start.up(2)}, start);
}
@Override
public void reset() {
super.reset();
numTicks = 0;
}
@Override
protected double calculateCost(CalculationContext context) {
return cost(context, src.x, src.y, src.z);
@@ -82,7 +77,7 @@ public class MovementPillar extends Movement {
return LADDER_UP_ONE_COST;
}
}
if (!context.hasThrowaway() && !ladder) {
if (!ladder && !context.canPlaceThrowawayAt(x, y, z)) {
return COST_INF;
}
double hardness = MovementHelper.getMiningDurationTicks(context, x, y + 2, z, toBreak, true);
@@ -148,28 +143,28 @@ public class MovementPillar extends Movement {
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING) {
if (state.getStatus() != MovementStatus.RUNNING) {
return state;
}
IBlockState fromDown = BlockStateInterface.get(src);
if (BlockStateInterface.isWater(fromDown.getBlock()) && BlockStateInterface.isWater(dest)) {
// stay centered while swimming up a water column
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.getBlockPosCenter(dest)), false));
Vec3d destCenter = Utils.getBlockPosCenter(dest);
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.getBlockPosCenter(dest)), false));
Vec3d destCenter = VecUtils.getBlockPosCenter(dest);
if (Math.abs(player().posX - destCenter.x) > 0.2 || Math.abs(player().posZ - destCenter.z) > 0.2) {
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
}
if (playerFeet().equals(dest)) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
return state.setStatus(MovementStatus.SUCCESS);
}
return state;
}
boolean ladder = fromDown.getBlock() instanceof BlockLadder || fromDown.getBlock() instanceof BlockVine;
boolean vine = fromDown.getBlock() instanceof BlockVine;
if (!ladder) {
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
Utils.getBlockPosCenter(positionToPlace),
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(mc.player.getPositionEyes(1.0F),
VecUtils.getBlockPosCenter(positionToPlace),
new Rotation(mc.player.rotationYaw, mc.player.rotationPitch)), true));
}
@@ -178,11 +173,11 @@ public class MovementPillar extends Movement {
BlockPos against = vine ? getAgainst(src) : src.offset(fromDown.getValue(BlockLadder.FACING).getOpposite());
if (against == null) {
logDebug("Unable to climb vines");
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state.setStatus(MovementStatus.UNREACHABLE);
}
if (playerFeet().equals(against.up()) || playerFeet().equals(dest)) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
return state.setStatus(MovementStatus.SUCCESS);
}
if (MovementHelper.isBottomSlab(src.down())) {
state.setInput(InputOverrideHandler.Input.JUMP, true);
@@ -198,28 +193,25 @@ public class MovementPillar extends Movement {
} else {
// Get ready to place a throwaway block
if (!MovementHelper.throwaway(true)) {
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state.setStatus(MovementStatus.UNREACHABLE);
}
numTicks++;
// If our Y coordinate is above our goal, stop jumping
state.setInput(InputOverrideHandler.Input.JUMP, player().posY < dest.getY());
state.setInput(InputOverrideHandler.Input.SNEAK, true);
// Otherwise jump
if (numTicks > 20) {
double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = player().posZ - (dest.getZ() + 0.5);
double dist = Math.sqrt(diffX * diffX + diffZ * diffZ);
if (dist > 0.17) {//why 0.17? because it seemed like a good number, that's why
//[explanation added after baritone port lol] also because it needs to be less than 0.2 because of the 0.3 sneak limit
//and 0.17 is reasonably less than 0.2
double diffX = player().posX - (dest.getX() + 0.5);
double diffZ = player().posZ - (dest.getZ() + 0.5);
double dist = Math.sqrt(diffX * diffX + diffZ * diffZ);
if (dist > 0.17) {//why 0.17? because it seemed like a good number, that's why
//[explanation added after baritone port lol] also because it needs to be less than 0.2 because of the 0.3 sneak limit
//and 0.17 is reasonably less than 0.2
// If it's been more than forty ticks of trying to jump and we aren't done yet, go forward, maybe we are stuck
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
}
// If it's been more than forty ticks of trying to jump and we aren't done yet, go forward, maybe we are stuck
state.setInput(InputOverrideHandler.Input.MOVE_FORWARD, true);
}
if (!blockIsThere) {
Block fr = BlockStateInterface.get(src).getBlock();
if (!(fr instanceof BlockAir || fr.isReplaceable(Minecraft.getMinecraft().world, src))) {
@@ -233,7 +225,7 @@ public class MovementPillar extends Movement {
// If we are at our goal and the block below us is placed
if (playerFeet().equals(dest) && blockIsThere) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
return state.setStatus(MovementStatus.SUCCESS);
}
return state;

View File

@@ -18,16 +18,14 @@
package baritone.pathing.movement.movements;
import baritone.Baritone;
import baritone.api.utils.Rotation;
import baritone.behavior.LookBehaviorUtils;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.utils.*;
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.InputOverrideHandler;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.*;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
@@ -67,8 +65,10 @@ public class MovementTraverse extends Movement {
Block srcDown = BlockStateInterface.getBlock(x, y - 1, z);
if (MovementHelper.canWalkOn(destX, y - 1, destZ, destOn)) {//this is a walk, not a bridge
double WC = WALK_ONE_BLOCK_COST;
boolean water = false;
if (BlockStateInterface.isWater(pb0.getBlock()) || BlockStateInterface.isWater(pb1.getBlock())) {
WC = WALK_ONE_IN_WATER_COST;
WC = context.waterWalkSpeed();
water = true;
} else {
if (destOn.getBlock() == Blocks.SOUL_SAND) {
WC += (WALK_ONE_OVER_SOUL_SAND_COST - WALK_ONE_BLOCK_COST) / 2;
@@ -83,10 +83,11 @@ public class MovementTraverse extends Movement {
}
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb1, false);
if (hardness1 == 0 && hardness2 == 0) {
if (WC == WALK_ONE_BLOCK_COST && context.canSprint()) {
// If there's nothing in the way, and this isn't water or soul sand, and we aren't sneak placing
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
WC = SPRINT_ONE_BLOCK_COST;
// Don't check for soul sand, since we can sprint on that too
WC *= SPRINT_MULTIPLIER;
}
return WC;
}
@@ -104,7 +105,7 @@ public class MovementTraverse extends Movement {
if (BlockStateInterface.isWater(destOn.getBlock()) && throughWater) {
return COST_INF;
}
if (!context.hasThrowaway()) {
if (!context.canPlaceThrowawayAt(destX, y - 1, destZ)) {
return COST_INF;
}
double hardness1 = MovementHelper.getMiningDurationTicks(context, destX, y, destZ, pb0, false);
@@ -113,7 +114,7 @@ public class MovementTraverse extends Movement {
}
double hardness2 = MovementHelper.getMiningDurationTicks(context, destX, y + 1, destZ, pb1, true);
double WC = throughWater ? WALK_ONE_IN_WATER_COST : WALK_ONE_BLOCK_COST;
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();
@@ -141,13 +142,13 @@ public class MovementTraverse extends Movement {
@Override
public MovementState updateState(MovementState state) {
super.updateState(state);
if (state.getStatus() != MovementState.MovementStatus.RUNNING) {
if (state.getStatus() != MovementStatus.RUNNING) {
// if the setting is enabled
if (!Baritone.settings().walkWhileBreaking.get()) {
return state;
}
// and if we're prepping (aka mining the block in front)
if (state.getStatus() != MovementState.MovementStatus.PREPPING) {
if (state.getStatus() != MovementStatus.PREPPING) {
return state;
}
// and if it's fine to walk into the blocks in front
@@ -165,7 +166,7 @@ public class MovementTraverse extends Movement {
// combine the yaw to the center of the destination, and the pitch to the specific block we're trying to break
// it's safe to do this since the two blocks we break (in a traverse) are right on top of each other and so will have the same yaw
float yawToDest = Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(dest, world())).getYaw();
float yawToDest = RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.calculateBlockCenter(dest)).getYaw();
float pitchToBreak = state.getTarget().getRotation().get().getPitch();
state.setTarget(new MovementState.MovementTarget(new Rotation(yawToDest, pitchToBreak), true));
@@ -190,7 +191,7 @@ public class MovementTraverse extends Movement {
}
if (isDoorActuallyBlockingUs) {
if (!(Blocks.IRON_DOOR.equals(pb0.getBlock()) || Blocks.IRON_DOOR.equals(pb1.getBlock()))) {
return state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(positionsToBreak[0], world())), true))
return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.calculateBlockCenter(positionsToBreak[0])), true))
.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
}
@@ -205,7 +206,7 @@ public class MovementTraverse extends Movement {
}
if (blocked != null) {
return state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), Utils.calcCenterFromCoords(blocked, world())), true))
return state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), VecUtils.calculateBlockCenter(blocked)), true))
.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
}
@@ -222,7 +223,7 @@ public class MovementTraverse extends Movement {
if (isTheBridgeBlockThere) {
if (playerFeet().equals(dest)) {
return state.setStatus(MovementState.MovementStatus.SUCCESS);
return state.setStatus(MovementStatus.SUCCESS);
}
if (wasTheBridgeBlockAlwaysThere && !BlockStateInterface.isLiquid(playerFeet())) {
state.setInput(InputOverrideHandler.Input.SPRINT, true);
@@ -245,7 +246,7 @@ public class MovementTraverse extends Movement {
if (MovementHelper.canPlaceAgainst(against1)) {
if (!MovementHelper.throwaway(true)) { // get ready to place a throwaway block
logDebug("bb pls get me some blocks. dirt or cobble");
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state.setStatus(MovementStatus.UNREACHABLE);
}
if (!Baritone.settings().assumeSafeWalk.get()) {
state.setInput(InputOverrideHandler.Input.SNEAK, true);
@@ -263,16 +264,16 @@ public class MovementTraverse extends Movement {
double faceX = (dest.getX() + against1.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + against1.getY()) * 0.5D;
double faceZ = (dest.getZ() + against1.getZ() + 1.0D) * 0.5D;
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
state.setTarget(new MovementState.MovementTarget(RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
EnumFacing side = Minecraft.getMinecraft().objectMouseOver.sideHit;
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), against1) && Minecraft.getMinecraft().player.isSneaking()) {
if (LookBehaviorUtils.getSelectedBlock().get().offset(side).equals(positionToPlace)) {
if (Objects.equals(RayTraceUtils.getSelectedBlock().orElse(null), against1) && (Minecraft.getMinecraft().player.isSneaking() || Baritone.settings().assumeSafeWalk.get())) {
if (RayTraceUtils.getSelectedBlock().get().offset(side).equals(positionToPlace)) {
return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true);
}
// wrong side?
}
System.out.println("Trying to look at " + against1 + ", actually looking at" + LookBehaviorUtils.getSelectedBlock());
//System.out.println("Trying to look at " + against1 + ", actually looking at" + RayTraceUtils.getSelectedBlock());
return state.setInput(InputOverrideHandler.Input.CLICK_LEFT, true);
}
}
@@ -284,18 +285,26 @@ public class MovementTraverse extends Movement {
// Out.log(from + " " + to + " " + faceX + "," + faceY + "," + faceZ + " " + whereAmI);
if (!MovementHelper.throwaway(true)) {// get ready to place a throwaway block
logDebug("bb pls get me some blocks. dirt or cobble");
return state.setStatus(MovementState.MovementStatus.UNREACHABLE);
return state.setStatus(MovementStatus.UNREACHABLE);
}
double faceX = (dest.getX() + src.getX() + 1.0D) * 0.5D;
double faceY = (dest.getY() + src.getY() - 1.0D) * 0.5D;
double faceZ = (dest.getZ() + src.getZ() + 1.0D) * 0.5D;
// faceX, faceY, faceZ is the middle of the face between from and to
BlockPos goalLook = src.down(); // this is the block we were just standing on, and the one we want to place against
state.setTarget(new MovementState.MovementTarget(Utils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations()), true));
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);
Rotation backToFace = RotationUtils.calcRotationFromVec3d(playerHead(), new Vec3d(faceX, faceY, faceZ), playerRotations());
float pitch = backToFace.getPitch();
double dist = Math.max(Math.abs(player().posX - faceX), Math.abs(player().posZ - faceZ));
if (dist < 0.29) {
float yaw = RotationUtils.calcRotationFromVec3d(VecUtils.getBlockPosCenter(dest), playerHead(), playerRotations()).getYaw();
state.setTarget(new MovementState.MovementTarget(new Rotation(yaw, pitch), true));
state.setInput(InputOverrideHandler.Input.MOVE_BACK, true);
} else {
state.setTarget(new MovementState.MovementTarget(backToFace, true));
}
state.setInput(InputOverrideHandler.Input.SNEAK, true);
if (Objects.equals(LookBehaviorUtils.getSelectedBlock().orElse(null), goalLook)) {
if (Objects.equals(RayTraceUtils.getSelectedBlock().orElse(null), goalLook)) {
return state.setInput(InputOverrideHandler.Input.CLICK_RIGHT, true); // wait to right click until we are able to place
}
// Out.log("Trying to look at " + goalLook + ", actually looking at" + Baritone.whatAreYouLookingAt());
@@ -308,6 +317,14 @@ public class MovementTraverse extends Movement {
}
}
@Override
public boolean safeToCancel(MovementState state) {
// if we're in the process of breaking blocks before walking forwards
// or if this isn't a sneak place (the block is already there)
// then it's safe to cancel this
return state.getStatus() != MovementStatus.RUNNING || MovementHelper.canWalkOn(dest.down());
}
@Override
protected boolean prepared(MovementState state) {
if (playerFeet().equals(src) || playerFeet().equals(src.down())) {

View File

@@ -19,22 +19,28 @@ package baritone.pathing.path;
import baritone.Baritone;
import baritone.api.event.events.TickEvent;
import baritone.api.pathing.calc.IPath;
import baritone.api.pathing.movement.ActionCosts;
import baritone.pathing.movement.*;
import baritone.api.pathing.movement.IMovement;
import baritone.api.pathing.movement.MovementStatus;
import baritone.api.pathing.path.IPathExecutor;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.VecUtils;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.movement.CalculationContext;
import baritone.pathing.movement.MovementHelper;
import baritone.pathing.movement.movements.*;
import baritone.utils.BlockBreakHelper;
import baritone.utils.BlockStateInterface;
import baritone.utils.Helper;
import baritone.utils.Utils;
import baritone.utils.pathing.BetterBlockPos;
import baritone.utils.InputOverrideHandler;
import net.minecraft.init.Blocks;
import net.minecraft.util.Tuple;
import net.minecraft.util.math.BlockPos;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.*;
import static baritone.pathing.movement.MovementState.MovementStatus.*;
import static baritone.api.pathing.movement.MovementStatus.*;
/**
* Behavior to execute a precomputed path. Does not (yet) deal with path segmentation or stitching
@@ -42,7 +48,7 @@ import static baritone.pathing.movement.MovementState.MovementStatus.*;
*
* @author leijurv
*/
public class PathExecutor implements Helper {
public class PathExecutor implements IPathExecutor, Helper {
private static final double MAX_MAX_DIST_FROM_PATH = 3;
private static final double MAX_DIST_FROM_PATH = 2;
@@ -110,24 +116,25 @@ public class PathExecutor implements Helper {
for (int j = pathPosition; j <= previousPos; j++) {
path.movements().get(j).reset();
}
clearKeys();
onChangeInPathPosition();
return false;
}
}
for (int i = pathPosition + 2; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing)
for (int i = pathPosition + 3; i < path.length(); i++) { //dont check pathPosition+1. the movement tells us when it's done (e.g. sneak placing)
// also don't check pathPosition+2 because reasons
if (whereAmI.equals(path.positions().get(i))) {
if (i - pathPosition > 2) {
logDebug("Skipping forward " + (i - pathPosition) + " steps, to " + i);
}
System.out.println("Double skip sundae");
//System.out.println("Double skip sundae");
pathPosition = i - 1;
clearKeys();
onChangeInPathPosition();
return false;
}
}
}
}
Tuple<Double, BlockPos> status = path.closestPathPos();
Tuple<Double, BlockPos> status = closestPathPos(path);
if (possiblyOffPath(status, MAX_DIST_FROM_PATH)) {
ticksAway++;
System.out.println("FAR AWAY FROM PATH FOR " + ticksAway + " TICKS. Current distance: " + status.getFirst() + ". Threshold: " + MAX_DIST_FROM_PATH);
@@ -176,18 +183,16 @@ public class PathExecutor implements Helper {
}
}
}*/
long start = System.nanoTime() / 1000000L;
//long start = System.nanoTime() / 1000000L;
for (int i = pathPosition - 10; i < pathPosition + 10; i++) {
if (i < 0 || i >= path.movements().size()) {
continue;
}
Movement m = path.movements().get(i);
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());
m.toBreakCached = null;
m.toPlaceCached = null;
m.toWalkIntoCached = null;
m.resetBlockCache();
if (!prevBreak.equals(new HashSet<>(m.toBreak()))) {
recalcBP = true;
}
@@ -212,17 +217,18 @@ public class PathExecutor implements Helper {
toWalkInto = newWalkInto;
recalcBP = false;
}
long end = System.nanoTime() / 1000000L;
/*long end = System.nanoTime() / 1000000L;
if (end - start > 0) {
System.out.println("Recalculating break and place took " + (end - start) + "ms");
}
Movement movement = path.movements().get(pathPosition);
}*/
IMovement movement = path.movements().get(pathPosition);
boolean canCancel = movement.safeToCancel();
if (costEstimateIndex == null || costEstimateIndex != pathPosition) {
costEstimateIndex = pathPosition;
// do this only once, when the movement starts, and deliberately get the cost as cached when this path was calculated, not the cost as it is right now
currentMovementOriginalCostEstimate = movement.getCost(null);
currentMovementOriginalCostEstimate = movement.getCost();
for (int i = 1; i < Baritone.settings().costVerificationLookahead.get() && pathPosition + i < path.length() - 1; i++) {
if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF) {
if (path.movements().get(pathPosition + i).calculateCostWithoutCaching() >= ActionCosts.COST_INF && canCancel) {
logDebug("Something has changed in the world and a future movement has become impossible. Cancelling.");
cancel();
return true;
@@ -230,17 +236,22 @@ public class PathExecutor implements Helper {
}
}
double currentCost = movement.recalculateCost();
if (currentCost >= ActionCosts.COST_INF) {
if (currentCost >= ActionCosts.COST_INF && canCancel) {
logDebug("Something has changed in the world and this movement has become impossible. Cancelling.");
cancel();
return true;
}
if (!movement.calculatedWhileLoaded() && currentCost - currentMovementOriginalCostEstimate > Baritone.settings().maxCostIncrease.get()) {
if (!movement.calculatedWhileLoaded() && currentCost - currentMovementOriginalCostEstimate > Baritone.settings().maxCostIncrease.get() && canCancel) {
logDebug("Original cost " + currentMovementOriginalCostEstimate + " current cost " + currentCost + ". Cancelling.");
cancel();
return true;
}
MovementState.MovementStatus movementStatus = movement.update();
if (shouldPause()) {
logDebug("Pausing since current best path is a backtrack");
clearKeys();
return true;
}
MovementStatus movementStatus = movement.update();
if (movementStatus == UNREACHABLE || movementStatus == FAILED) {
logDebug("Movement returns status " + movementStatus);
cancel();
@@ -249,8 +260,7 @@ public class PathExecutor implements Helper {
if (movementStatus == SUCCESS) {
//System.out.println("Movement done, next path");
pathPosition++;
ticksOnCurrent = 0;
clearKeys();
onChangeInPathPosition();
onTick(event);
return true;
} else {
@@ -269,13 +279,59 @@ public class PathExecutor implements Helper {
return false; // movement is in progress
}
private Tuple<Double, BlockPos> closestPathPos(IPath path) {
double best = -1;
BlockPos bestPos = null;
for (BlockPos pos : path.positions()) {
double dist = VecUtils.entityDistanceToCenter(player(), pos);
if (dist < best || best == -1) {
best = dist;
bestPos = pos;
}
}
return new Tuple<>(best, bestPos);
}
private boolean shouldPause() {
Optional<AbstractNodeCostSearch> current = AbstractNodeCostSearch.getCurrentlyRunning();
if (!current.isPresent()) {
return false;
}
if (!player().onGround) {
return false;
}
if (!MovementHelper.canWalkOn(playerFeet().down())) {
// we're in some kind of sketchy situation, maybe parkouring
return false;
}
if (!MovementHelper.canWalkThrough(playerFeet()) || !MovementHelper.canWalkThrough(playerFeet().up())) {
// suffocating?
return false;
}
if (!path.movements().get(pathPosition).safeToCancel()) {
return false;
}
Optional<IPath> currentBest = current.get().bestPathSoFar();
if (!currentBest.isPresent()) {
return false;
}
List<BetterBlockPos> positions = currentBest.get().positions();
if (positions.size() < 3) {
return false; // not long enough yet to justify pausing, its far from certain we'll actually take this route
}
// the first block of the next path will always overlap
// no need to pause our very last movement when it would have otherwise cleanly exited with MovementStatus SUCCESS
positions = positions.subList(1, positions.size());
return positions.contains(playerFeet());
}
private boolean possiblyOffPath(Tuple<Double, BlockPos> status, double leniency) {
double distanceFromPath = status.getFirst();
if (distanceFromPath > leniency) {
// when we're midair in the middle of a fall, we're very far from both the beginning and the end, but we aren't actually off path
if (path.movements().get(pathPosition) instanceof MovementFall) {
BlockPos fallDest = path.positions().get(pathPosition + 1); // .get(pathPosition) is the block we fell off of
if (Utils.playerFlatDistanceToCenter(fallDest) < leniency) { // ignore Y by using flat distance
if (VecUtils.entityFlatDistanceToCenter(player(), fallDest) < leniency) { // ignore Y by using flat distance
return false;
}
return true;
@@ -287,10 +343,24 @@ public class PathExecutor implements Helper {
}
}
/**
* Regardless of current path position, snap to the current player feet if possible
*/
public boolean snipsnapifpossible() {
int index = path.positions().indexOf(playerFeet());
if (index == -1) {
return false;
}
pathPosition = index;
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().canSprint()) {
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(InputOverrideHandler.Input.SPRINT, false);
player().setSprinting(false);
return;
}
@@ -303,8 +373,11 @@ public class PathExecutor implements Helper {
return;
}
// we'll take it from here, no need for minecraft to see we're holding down control and sprint for us
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(InputOverrideHandler.Input.SPRINT, false);
// however, descend doesn't request sprinting, beceause it doesn't know the context of what movement comes after it
Movement current = path.movements().get(pathPosition);
IMovement current = path.movements().get(pathPosition);
if (current instanceof MovementDescend && pathPosition < path.length() - 2) {
// (dest - src) + dest is offset 1 more in the same direction
@@ -319,11 +392,21 @@ public class PathExecutor implements Helper {
}
}
Movement next = path.movements().get(pathPosition + 1);
IMovement next = path.movements().get(pathPosition + 1);
if (next instanceof MovementAscend && current.getDirection().up().equals(next.getDirection().down())) {
// a descend then an ascend in the same direction
if (!player().isSprinting()) {
player().setSprinting(true);
}
pathPosition++;
// okay to skip clearKeys and / or onChangeInPathPosition here since this isn't possible to repeat, since it's asymmetric
logDebug("Skipping descend to straight ascend");
return;
}
if (canSprintInto(current, next)) {
if (playerFeet().equals(current.getDest())) {
pathPosition++;
clearKeys();
onChangeInPathPosition();
}
if (!player().isSprinting()) {
player().setSprinting(true);
@@ -332,10 +415,23 @@ public class PathExecutor implements Helper {
}
//logDebug("Turning off sprinting " + movement + " " + next + " " + movement.getDirection() + " " + next.getDirection().down() + " " + next.getDirection().down().equals(movement.getDirection()));
}
if (current instanceof MovementAscend && pathPosition != 0) {
IMovement prev = path.movements().get(pathPosition - 1);
if (prev instanceof MovementDescend && prev.getDirection().up().equals(current.getDirection().down())) {
BlockPos center = current.getSrc().up();
if (player().posY >= center.getY()) { // playerFeet adds 0.1251 to account for soul sand
Baritone.INSTANCE.getInputOverrideHandler().setInputForceState(InputOverrideHandler.Input.JUMP, false);
if (!player().isSprinting()) {
player().setSprinting(true);
}
return;
}
}
}
player().setSprinting(false);
}
private static boolean canSprintInto(Movement current, Movement next) {
private static boolean canSprintInto(IMovement current, IMovement next) {
if (next instanceof MovementDescend) {
if (next.getDirection().equals(current.getDirection())) {
return true;
@@ -352,6 +448,11 @@ public class PathExecutor implements Helper {
return false;
}
private void onChangeInPathPosition() {
clearKeys();
ticksOnCurrent = 0;
}
private static void clearKeys() {
// i'm just sick and tired of this snippet being everywhere lol
Baritone.INSTANCE.getInputOverrideHandler().clearAllKeys();
@@ -359,6 +460,7 @@ public class PathExecutor implements Helper {
private void cancel() {
clearKeys();
BlockBreakHelper.stopBreakingBlock();
pathPosition = path.length() + 3;
failed = true;
}
@@ -367,6 +469,7 @@ public class PathExecutor implements Helper {
return pathPosition;
}
@Override
public IPath getPath() {
return path;
}

View File

@@ -22,51 +22,105 @@ import baritone.api.event.listener.AbstractGameEventListener;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalBlock;
import baritone.behavior.PathingBehavior;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiMainMenu;
import net.minecraft.client.settings.GameSettings;
import net.minecraft.client.tutorial.TutorialSteps;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.GameType;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.WorldType;
public class BaritoneAutoTest implements AbstractGameEventListener, Helper {
public static final boolean ENABLE_AUTO_TEST = true;
public static final BaritoneAutoTest INSTANCE = new BaritoneAutoTest();
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(50, 65, 50);
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 = 3200;
private static final int MAX_TICKS = 3500;
/**
* Called right after the {@link GameSettings} object is created in the {@link Minecraft} instance.
*/
public void onPreInit() {
if (!BaritoneAutoTest.ENABLE_AUTO_TEST) {
return;
}
System.out.println("Optimizing Game Settings");
GameSettings s = mc.gameSettings;
s.limitFramerate = 20;
s.mipmapLevels = 0;
s.particleSetting = 2;
s.overrideWidth = 128;
s.overrideHeight = 128;
s.heldItemTooltips = false;
s.entityShadows = false;
s.chatScale = 0.0F;
s.ambientOcclusion = 0;
s.clouds = 0;
s.fancyGraphics = false;
s.tutorialStep = TutorialSteps.NONE;
s.hideGUI = true;
s.fovSetting = 30.0F;
}
@Override
public void onTick(TickEvent event) {
if (mc.currentScreen != null && mc.currentScreen instanceof GuiMainMenu) {
// If we're on the main menu then create the test world and launch the integrated server
if (mc.currentScreen instanceof GuiMainMenu) {
System.out.println("Beginning Baritone automatic test routine");
mc.displayGuiScreen(null);
WorldSettings worldsettings = new WorldSettings(TEST_SEED, GameType.getByName("survival"), true, false, WorldType.DEFAULT);
worldsettings.setGeneratorOptions("");
mc.launchIntegratedServer("BaritoneAutoTest", "BaritoneAutoTest", worldsettings);
}
// If the integrated server is launched and the world has initialized, set the spawn point
// to our defined starting position
if (mc.getIntegratedServer() != null && mc.getIntegratedServer().worlds[0] != null) {
mc.getIntegratedServer().worlds[0].setSpawnPoint(STARTING_POSITION);
mc.getIntegratedServer().worlds[0].getGameRules().setOrCreateGameRule("spawnRadius", "0");
}
if (event.getType() == TickEvent.Type.IN) {
if (event.getType() == TickEvent.Type.IN) { // If we're in-game
// Force the integrated server to share the world to LAN so that
// the ingame pause menu gui doesn't actually pause our game
if (mc.isSingleplayer() && !mc.getIntegratedServer().getPublic()) {
mc.getIntegratedServer().shareToLAN(GameType.getByName("survival"), false);
}
if (event.getCount() < 100) {
// For the first 200 ticks, wait for the world to generate
if (event.getCount() < 200) {
System.out.println("Waiting for world to generate... " + event.getCount());
return;
}
if (event.getCount() % 100 == 0) { // print only once every 5 seconds
// Print out an update of our position every 5 seconds
if (event.getCount() % 100 == 0) {
System.out.println(playerFeet() + " " + event.getCount());
}
// Setup Baritone's pathing goal and (if needed) begin pathing
PathingBehavior.INSTANCE.setGoal(GOAL);
PathingBehavior.INSTANCE.path();
// If we have reached our goal, print a message and safely close the game
if (GOAL.isInGoal(playerFeet())) {
System.out.println("Successfully pathed to " + playerFeet() + " in " + event.getCount() + " ticks");
mc.shutdown();
}
// If we have exceeded the expected number of ticks to complete the pathing
// task, then throw an IllegalStateException to cause the build to fail
if (event.getCount() > MAX_TICKS) {
throw new IllegalStateException("took too long");
}
}
}
private BaritoneAutoTest() {}
}

View File

@@ -38,7 +38,7 @@ public class BlockStateInterface implements Helper {
private static Chunk prev = null;
private static CachedRegion prevCached = null;
private static IBlockState AIR = Blocks.AIR.getDefaultState();
private static final IBlockState AIR = Blocks.AIR.getDefaultState();
public static IBlockState get(BlockPos pos) {
return get(pos.getX(), pos.getY(), pos.getZ());

View File

@@ -23,6 +23,8 @@ import baritone.api.cache.IWaypoint;
import baritone.api.event.events.ChatEvent;
import baritone.api.pathing.goals.*;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.RayTraceUtils;
import baritone.api.utils.SettingsUtil;
import baritone.behavior.Behavior;
import baritone.behavior.FollowBehavior;
import baritone.behavior.MineBehavior;
@@ -31,7 +33,8 @@ import baritone.cache.ChunkPacker;
import baritone.cache.Waypoint;
import baritone.cache.WorldProvider;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.movement.*;
import baritone.pathing.movement.Movement;
import baritone.pathing.movement.Moves;
import net.minecraft.block.Block;
import net.minecraft.client.multiplayer.ChunkProviderClient;
import net.minecraft.entity.Entity;
@@ -76,6 +79,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
setting.value ^= true;
event.cancel();
logDirect("Toggled " + setting.getName() + " to " + setting.value);
SettingsUtil.save(Baritone.settings());
return;
}
}
@@ -109,6 +113,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel();
return;
}
SettingsUtil.save(Baritone.settings());
logDirect(setting.toString());
event.cancel();
return;
@@ -198,7 +203,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel();
return;
}
if (msg.equals("cancel")) {
if (msg.equals("cancel") || msg.equals("stop")) {
MineBehavior.INSTANCE.cancel();
FollowBehavior.INSTANCE.cancel();
PathingBehavior.INSTANCE.cancel();
@@ -250,7 +255,7 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
String name = msg.substring(6).trim();
Optional<Entity> toFollow = Optional.empty();
if (name.length() == 0) {
toFollow = MovementHelper.whatEntityAmILookingAt();
toFollow = RayTraceUtils.getSelectedEntity();
} else {
for (EntityPlayer pl : world().playerEntities) {
String theirName = pl.getName().trim().toLowerCase();
@@ -464,10 +469,10 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
while (moves.contains(null)) {
moves.remove(null);
}
moves.sort(Comparator.comparingDouble(movement -> movement.getCost(new CalculationContext())));
moves.sort(Comparator.comparingDouble(Movement::getCost));
for (Movement move : moves) {
String[] parts = move.getClass().toString().split("\\.");
double cost = move.getCost(new CalculationContext());
double cost = move.getCost();
String strCost = cost + "";
if (cost >= ActionCosts.COST_INF) {
strCost = "IMPOSSIBLE";
@@ -477,5 +482,15 @@ public class ExampleBaritoneControl extends Behavior implements Helper {
event.cancel();
return;
}
if (msg.equals("pause")) {
boolean enabled = PathingBehavior.INSTANCE.toggle();
logDirect("Pathing Behavior has " + (enabled ? "resumed" : "paused") + ".");
event.cancel();
return;
}
if (msg.equals("damn")) {
logDirect("daniel");
return;
}
}
}

View File

@@ -18,8 +18,8 @@
package baritone.utils;
import baritone.Baritone;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.Rotation;
import baritone.utils.pathing.BetterBlockPos;
import net.minecraft.block.BlockSlab;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -86,8 +86,8 @@ public interface Helper {
*/
default void logDebug(String message) {
if (!Baritone.settings().chatDebug.get()) {
System.out.println("Suppressed debug message:");
System.out.println(message);
//System.out.println("Suppressed debug message:");
//System.out.println(message);
return;
}
logDirect(message);

View File

@@ -18,13 +18,17 @@
package baritone.utils;
import baritone.Baritone;
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.pathing.path.IPath;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.interfaces.IGoalRenderPos;
import baritone.utils.pathing.BetterBlockPos;
import baritone.behavior.PathingBehavior;
import baritone.pathing.calc.AbstractNodeCostSearch;
import baritone.pathing.path.PathExecutor;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
@@ -40,6 +44,7 @@ import net.minecraft.util.math.MathHelper;
import java.awt.*;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.lwjgl.opengl.GL11.*;
@@ -49,12 +54,68 @@ import static org.lwjgl.opengl.GL11.*;
* @since 8/9/2018 4:39 PM
*/
public final class PathRenderer implements Helper {
private static final Tessellator TESSELLATOR = Tessellator.getInstance();
private static final BufferBuilder BUFFER = TESSELLATOR.getBuffer();
private PathRenderer() {}
public static void render(RenderEvent event, PathingBehavior behavior) {
// System.out.println("Render passing");
// System.out.println(event.getPartialTicks());
float partialTicks = event.getPartialTicks();
Goal goal = behavior.getGoal();
EntityPlayerSP player = mc.player;
if (goal != null && Baritone.settings().renderGoal.value) {
drawLitDankGoalBox(player, goal, partialTicks, Baritone.settings().colorGoalBox.get());
}
if (!Baritone.settings().renderPath.get()) {
return;
}
//drawManySelectionBoxes(player, Collections.singletonList(behavior.pathStart()), partialTicks, Color.WHITE);
//long start = System.nanoTime();
PathExecutor current = behavior.getCurrent(); // this should prevent most race conditions?
PathExecutor next = behavior.getNext(); // like, now it's not possible for current!=null to be true, then suddenly false because of another thread
// TODO is this enough, or do we need to acquire a lock here?
// TODO benchmark synchronized in render loop
// Render the current path, if there is one
if (current != null && current.getPath() != null) {
int renderBegin = Math.max(current.getPosition() - 3, 0);
drawPath(current.getPath(), renderBegin, player, partialTicks, Baritone.settings().colorCurrentPath.get(), Baritone.settings().fadePath.get(), 10, 20);
}
if (next != null && next.getPath() != null) {
drawPath(next.getPath(), 0, player, partialTicks, Baritone.settings().colorNextPath.get(), Baritone.settings().fadePath.get(), 10, 20);
}
//long split = System.nanoTime();
if (current != null) {
drawManySelectionBoxes(player, current.toBreak(), partialTicks, Baritone.settings().colorBlocksToBreak.get());
drawManySelectionBoxes(player, current.toPlace(), partialTicks, Baritone.settings().colorBlocksToPlace.get());
drawManySelectionBoxes(player, current.toWalkInto(), partialTicks, Baritone.settings().colorBlocksToWalkInto.get());
}
// If there is a path calculation currently running, render the path calculation process
AbstractNodeCostSearch.getCurrentlyRunning().ifPresent(currentlyRunning -> {
currentlyRunning.bestPathSoFar().ifPresent(p -> {
drawPath(p, 0, player, partialTicks, Baritone.settings().colorBestPathSoFar.get(), Baritone.settings().fadePath.get(), 10, 20);
});
currentlyRunning.pathToMostRecentNodeConsidered().ifPresent(mr -> {
drawPath(mr, 0, player, partialTicks, Baritone.settings().colorMostRecentConsidered.get(), Baritone.settings().fadePath.get(), 10, 20);
drawManySelectionBoxes(player, Collections.singletonList(mr.getDest()), partialTicks, Baritone.settings().colorMostRecentConsidered.get());
});
});
//long end = System.nanoTime();
//System.out.println((end - split) + " " + (split - start));
// if (end - start > 0) {
// System.out.println("Frame took " + (split - start) + " " + (end - split));
//}
}
public static void drawPath(IPath path, int startIndex, EntityPlayerSP player, float partialTicks, Color color, boolean fadeOut, int fadeStart0, int fadeEnd0) {
GlStateManager.enableBlend();
GlStateManager.tryBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
@@ -62,28 +123,33 @@ public final class PathRenderer implements Helper {
GlStateManager.glLineWidth(Baritone.settings().pathRenderLineWidthPixels.get());
GlStateManager.disableTexture2D();
GlStateManager.depthMask(false);
if (Baritone.settings().renderPathIgnoreDepth.get()) {
GlStateManager.disableDepth();
}
List<BetterBlockPos> positions = path.positions();
int next;
Tessellator tessellator = Tessellator.getInstance();
int fadeStart = fadeStart0 + startIndex;
int fadeEnd = fadeEnd0 + startIndex;
for (int i = startIndex; i < positions.size() - 1; i = next) {
BlockPos start = positions.get(i);
BetterBlockPos start = positions.get(i);
next = i + 1;
BlockPos end = positions.get(next);
BetterBlockPos end = positions.get(next);
BlockPos direction = Utils.diff(start, end);
while (next + 1 < positions.size() && (!fadeOut || next + 1 < fadeStart) && direction.equals(Utils.diff(end, positions.get(next + 1)))) {
int dirX = end.x - start.x;
int dirY = end.y - start.y;
int dirZ = end.z - start.z;
while (next + 1 < positions.size() && (!fadeOut || next + 1 < fadeStart) && (dirX == positions.get(next + 1).x - end.x && dirY == positions.get(next + 1).y - end.y && dirZ == positions.get(next + 1).z - end.z)) {
next++;
end = positions.get(next);
}
double x1 = start.getX();
double y1 = start.getY();
double z1 = start.getZ();
double x2 = end.getX();
double y2 = end.getY();
double z2 = end.getZ();
double x1 = start.x;
double y1 = start.y;
double z1 = start.z;
double x2 = end.x;
double y2 = end.y;
double z2 = end.z;
if (fadeOut) {
float alpha;
@@ -100,6 +166,9 @@ public final class PathRenderer implements Helper {
drawLine(player, x1, y1, z1, x2, y2, z2, partialTicks);
tessellator.draw();
}
if (Baritone.settings().renderPathIgnoreDepth.get()) {
GlStateManager.enableDepth();
}
//GlStateManager.color(0.0f, 0.0f, 0.0f, 0.4f);
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
@@ -125,6 +194,11 @@ public final class PathRenderer implements Helper {
GlStateManager.glLineWidth(Baritone.settings().pathRenderLineWidthPixels.get());
GlStateManager.disableTexture2D();
GlStateManager.depthMask(false);
if (Baritone.settings().renderSelectionBoxesIgnoreDepth.get()) {
GlStateManager.disableDepth();
}
float expand = 0.002F;
//BlockPos blockpos = movingObjectPositionIn.getBlockPos();
@@ -166,6 +240,10 @@ public final class PathRenderer implements Helper {
TESSELLATOR.draw();
});
if (Baritone.settings().renderSelectionBoxesIgnoreDepth.get()) {
GlStateManager.enableDepth();
}
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
@@ -230,26 +308,12 @@ public final class PathRenderer implements Helper {
GlStateManager.glLineWidth(Baritone.settings().goalRenderLineWidthPixels.get());
GlStateManager.disableTexture2D();
GlStateManager.depthMask(false);
if (y1 != 0) {
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(minX, y1, minZ).endVertex();
BUFFER.pos(maxX, y1, minZ).endVertex();
BUFFER.pos(maxX, y1, maxZ).endVertex();
BUFFER.pos(minX, y1, maxZ).endVertex();
BUFFER.pos(minX, y1, minZ).endVertex();
TESSELLATOR.draw();
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
GlStateManager.disableDepth();
}
if (y2 != 0) {
BUFFER.begin(GL_LINE_STRIP, DefaultVertexFormats.POSITION);
BUFFER.pos(minX, y2, minZ).endVertex();
BUFFER.pos(maxX, y2, minZ).endVertex();
BUFFER.pos(maxX, y2, maxZ).endVertex();
BUFFER.pos(minX, y2, maxZ).endVertex();
BUFFER.pos(minX, y2, minZ).endVertex();
TESSELLATOR.draw();
}
renderHorizontalQuad(minX, maxX, minZ, maxZ, y1);
renderHorizontalQuad(minX, maxX, minZ, maxZ, y2);
BUFFER.begin(GL_LINES, DefaultVertexFormats.POSITION);
BUFFER.pos(minX, minY, minZ).endVertex();
@@ -262,9 +326,22 @@ public final class PathRenderer implements Helper {
BUFFER.pos(minX, maxY, maxZ).endVertex();
TESSELLATOR.draw();
if (Baritone.settings().renderGoalIgnoreDepth.get()) {
GlStateManager.enableDepth();
}
GlStateManager.depthMask(true);
GlStateManager.enableTexture2D();
GlStateManager.disableBlend();
}
private static void renderHorizontalQuad(double minX, double maxX, double minZ, double maxZ, double y) {
if (y != 0) {
BUFFER.begin(GL_LINE_LOOP, DefaultVertexFormats.POSITION);
BUFFER.pos(minX, y, minZ).endVertex();
BUFFER.pos(maxX, y, minZ).endVertex();
BUFFER.pos(maxX, y, maxZ).endVertex();
BUFFER.pos(minX, y, maxZ).endVertex();
TESSELLATOR.draw();
}
}
}

View File

@@ -67,7 +67,14 @@ public class ToolSet implements Helper {
* @return how long it would take in ticks
*/
public double getStrVsBlock(IBlockState state) {
return this.breakStrengthCache.computeIfAbsent(state.getBlock(), b -> calculateStrVsBlock(getBestSlot(state), state));
Double strength = this.breakStrengthCache.get(state.getBlock());
if (strength != null) {
// the function will take this path >99% of the time
return strength;
}
double str = calculateStrVsBlock(getBestSlot(state), state);
this.breakStrengthCache.put(state.getBlock(), str);
return str;
}
/**

View File

@@ -1,137 +0,0 @@
/*
* 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.Rotation;
import net.minecraft.block.BlockFire;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.util.math.AxisAlignedBB;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import static baritone.utils.Helper.HELPER;
/**
* @author Brady
* @since 8/1/2018 12:56 AM
*/
public final class Utils {
/**
* Constant that a degree value is multiplied by to get the equivalent radian value
*/
public static final double DEG_TO_RAD = Math.PI / 180.0;
/**
* Constant that a radian value is multiplied by to get the equivalent degree value
*/
public static final double RAD_TO_DEG = 180.0 / Math.PI;
public static Rotation calcRotationFromCoords(BlockPos orig, BlockPos dest) {
return calcRotationFromVec3d(vec3dFromBlockPos(orig), vec3dFromBlockPos(dest));
}
/**
* Calculates rotation to given Vec<sub>dest</sub> from Vec<sub>orig</sub>
*
* @param orig
* @param dest
* @return Rotation {@link Rotation}
*/
public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest) {
double[] delta = {orig.x - dest.x, orig.y - dest.y, orig.z - dest.z};
double yaw = MathHelper.atan2(delta[0], -delta[2]);
double dist = Math.sqrt(delta[0] * delta[0] + delta[2] * delta[2]);
double pitch = MathHelper.atan2(delta[1], dist);
return new Rotation(
(float) radToDeg(yaw),
(float) radToDeg(pitch)
);
}
/**
* Calculates rotation to given Vec<sub>dest</sub> from Vec<sub>orig</sub>
*
* @param orig
* @param dest
* @return Rotation {@link Rotation}
*/
public static Rotation calcRotationFromVec3d(Vec3d orig, Vec3d dest, Rotation current) {
return wrapAnglesToRelative(current, calcRotationFromVec3d(orig, dest));
}
public static Vec3d calcCenterFromCoords(BlockPos orig, World world) {
IBlockState b = BlockStateInterface.get(orig);
AxisAlignedBB bbox = b.getBoundingBox(world, orig);
double xDiff = (bbox.minX + bbox.maxX) / 2;
double yDiff = (bbox.minY + bbox.maxY) / 2;
double zDiff = (bbox.minZ + bbox.maxZ) / 2;
if (b.getBlock() instanceof BlockFire) {//look at bottom of fire when putting it out
yDiff = 0;
}
return new Vec3d(
orig.getX() + xDiff,
orig.getY() + yDiff,
orig.getZ() + zDiff
);
}
public static Vec3d getBlockPosCenter(BlockPos pos) {
return new Vec3d(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5);
}
public static Rotation wrapAnglesToRelative(Rotation current, Rotation target) {
return target.subtract(current).normalize().add(current);
}
public static Vec3d vec3dFromBlockPos(BlockPos orig) {
return new Vec3d(orig.getX() + 0.0D, orig.getY() + 0.0D, orig.getZ() + 0.0D);
}
public static double distanceToCenter(BlockPos pos, double x, double y, double z) {
double xdiff = x - (pos.getX() + 0.5D);
double ydiff = y - (pos.getY() + 0.5D);
double zdiff = z - (pos.getZ() + 0.5D);
return Math.sqrt(xdiff * xdiff + ydiff * ydiff + zdiff * zdiff);
}
public static double playerDistanceToCenter(BlockPos pos) {
EntityPlayerSP player = HELPER.player();
return distanceToCenter(pos, player.posX, player.posY, player.posZ);
}
public static double playerFlatDistanceToCenter(BlockPos pos) {
EntityPlayerSP player = HELPER.player();
return distanceToCenter(pos, player.posX, pos.getY() + 0.5, player.posZ);
}
public static double degToRad(double deg) {
return deg * DEG_TO_RAD;
}
public static double radToDeg(double rad) {
return rad * RAD_TO_DEG;
}
public static BlockPos diff(BlockPos a, BlockPos b) {
return new BlockPos(a.getX() - b.getX(), a.getY() - b.getY(), a.getZ() - b.getZ());
}
}

View File

@@ -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.utils.pathing;
import baritone.utils.Helper;
import net.minecraft.world.border.WorldBorder;
public class BetterWorldBorder implements Helper {
private final double minX;
private final double maxX;
private final double minZ;
private final double maxZ;
public BetterWorldBorder(WorldBorder border) {
this.minX = border.minX();
this.maxX = border.maxX();
this.minZ = border.minZ();
this.maxZ = border.maxZ();
}
public boolean entirelyContains(int x, int z) {
return x + 1 > minX && x < maxX && z + 1 > minZ && z < maxZ;
}
public boolean canPlaceAt(int x, int z) {
// move it in 1 block on all sides
// because we can't place a block at the very edge against a block outside the border
// it won't let us right click it
return x > minX && x + 1 < maxX && z > minZ && z + 1 < maxZ;
}
}

View File

@@ -17,24 +17,27 @@
package baritone.utils.pathing;
import static baritone.api.pathing.movement.ActionCosts.COST_INF;
import baritone.api.pathing.movement.ActionCosts;
/**
* The result of a calculated movement, with destination x, y, z, and the cost of performing the movement
*
* @author leijurv
*/
public final class MoveResult {
public static final MoveResult IMPOSSIBLE = new MoveResult(0, 0, 0, COST_INF);
public final int destX;
public final int destY;
public final int destZ;
public final double cost;
public final class MutableMoveResult {
public int x;
public int y;
public int z;
public double cost;
public MoveResult(int x, int y, int z, double cost) {
this.destX = x;
this.destY = y;
this.destZ = z;
this.cost = cost;
public MutableMoveResult() {
reset();
}
public final void reset() {
x = 0;
y = 0;
z = 0;
cost = ActionCosts.COST_INF;
}
}

View File

@@ -0,0 +1 @@
baritone.BaritoneProvider

View File

@@ -17,6 +17,7 @@
package baritone.utils.pathing;
import baritone.api.utils.BetterBlockPos;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import org.junit.Test;