Compare commits

...

475 Commits

Author SHA1 Message Date
Leijurv
4bea9dfb42 started on simultaneous dijkstra scaffolder, saving progress here for now 2023-04-10 00:14:13 -07:00
Leijurv
f039a9cff8 belongs at bottom 2023-04-07 22:12:57 -07:00
Leijurv
06d18c4500 shouldnt have been separated 2023-04-07 20:45:08 -07:00
Leijurv
cc6228dced better test 2023-04-07 20:44:04 -07:00
Leijurv
0ed1c31106 more test 2023-04-07 20:37:32 -07:00
Leijurv
8c118401f3 blip staircases work 2023-04-07 17:47:29 -07:00
Leijurv
3e17352e99 navigablesurface now relies on full playerphysics and somehow it's FASTER??? 2023-04-06 23:43:41 -07:00
Leijurv
d594b15e40 abstract away the specific attachment from the impl of a player physics tracking navigable surface 2023-04-06 22:08:54 -07:00
Leijurv
c48d47ff2c no longer required 2023-04-06 21:25:53 -07:00
Leijurv
361c769650 more testing 2023-04-05 23:32:40 -07:00
Leijurv
294e847f19 refactors 2023-04-05 00:22:15 -07:00
Leijurv
c9bfcb417e compare with/without random splays before/during connection tests 2023-04-04 01:44:43 -07:00
Leijurv
1fc3155e9c more explanation 2023-04-02 23:19:38 -07:00
Leijurv
a9d6aaebf3 misc 2023-04-02 15:12:07 -07:00
Leijurv
b2ffa7de1b improved playerphysicstest actually caught a real bug 2023-03-27 23:17:12 +09:00
Leijurv
5ad90997ff player physics with bidirectional movement with tests, intended for use in navigable surface (because euler tour forests require an undirected graph) 2023-03-27 09:14:30 +09:00
Leijurv
b3afa98958 got a little carried away testing navigable surface 2023-03-23 21:43:37 -07:00
Leijurv
d2a5199383 unzobrist test just to make sure 2023-03-23 21:19:49 -07:00
Leijurv
d32973cae4 equals and hashcode for navigable surface tree attachment 2023-03-21 00:42:09 -07:00
Leijurv
f5dc6a034b refactor conngraphtest since i wrote part of it 2023-03-21 00:37:51 -07:00
Leijurv
06590f487b refactor and integrate redblacknode repo 2023-03-21 00:36:43 -07:00
Leijurv
3549a55f1e Merge remote-tracking branch 'rbn/trimmed' into builder-2 2023-03-21 00:26:43 -07:00
Leijurv
b8608c98e7 deleting these files to make way for merge of unrelated git history 2023-03-21 00:26:11 -07:00
Leijurv
e15cf933aa don't need tree list 2023-03-21 00:25:23 -07:00
Leijurv
8812f3027b trimmed for merge 2023-03-21 00:22:45 -07:00
Leijurv
69b36eea4b only run once 2023-03-21 00:11:27 -07:00
Leijurv
af320bd052 refactor and integrate 2023-03-21 00:11:04 -07:00
Leijurv
317f07283e integrate betterblockpos 2023-03-21 00:00:53 -07:00
Leijurv
bce0d47f95 tweak for older version of fastutil 2023-03-20 23:58:25 -07:00
Leijurv
b8d4c72a92 Merge remote-tracking branch 'dyncon/trimmed' into builder-2 2023-03-20 23:55:09 -07:00
Leijurv
0f5ee85e19 trim for merge 2023-03-20 23:54:02 -07:00
Leijurv
e7f54ab81d switch from integer to custom tree attachment 2023-03-20 23:51:19 -07:00
Leijurv
6fea22dc9f this is incredibly cool and it does figure out the staircase pattern like i hoped 2023-03-16 00:42:23 -07:00
Leijurv
2cb46e0540 explanatory readme 2023-03-16 00:18:38 -07:00
Leijurv
79113cf9a0 Merge branch 'long-map' into baritone-testing 2023-03-15 22:41:46 -07:00
Leijurv
fe808a5f83 test 2023-03-15 22:41:42 -07:00
Leijurv
200e68a1b9 import from baritone builder-2 2023-03-15 22:35:40 -07:00
Leijurv
59be6b4606 dead link 2023-03-15 14:56:13 -07:00
Leijurv
236d171d15 just in case anyone is curious, check in my partial impl from last year of euler tour forests over splay nodes (it was too intimidating to fully reimpl on top of a red-black or avl tree) 2023-03-15 14:54:13 -07:00
Leijurv
7ee6b40815 and i guess this should also use long instead of connvertex 2023-03-15 14:12:14 -07:00
Leijurv
49b620a7cf just checking if a long map could be faster, doesnt seem to matter (yet?) 2023-03-15 13:59:57 -07:00
Leijurv
52f795c3ae ram usage of empty hashmap buckets doesn't affect my use case 2023-03-15 13:43:39 -07:00
Leijurv
c177d6c708 need more heap 2023-03-15 13:39:27 -07:00
Leijurv
9870cbddc3 supposedly need to bump junit 2023-03-15 13:33:22 -07:00
Leijurv
8ee36bcd46 reformat all code 2023-03-15 13:30:23 -07:00
Leijurv
2af6dec3df switch from maven to gradle 2023-03-15 13:26:44 -07:00
Leijurv
802c81d766 bring in red black node 2023-03-15 13:23:39 -07:00
Leijurv
3a8c6712b1 satisfied with benchmark 2023-03-15 13:16:14 -07:00
Leijurv
f378578ada misc intellij 2023-03-15 13:16:08 -07:00
Leijurv
92447c0b5c dijkstra tweaks 2023-03-14 18:13:21 -07:00
Leijurv
023bebee66 more tests and sanity checks around collapsing components 2023-03-08 16:17:18 -08:00
Leijurv
cadf7a06d0 refactor per state with scaffolding into place order dependency graph 2023-03-08 13:49:20 -08:00
Leijurv
19c9238ea2 comments and thoughts about component merge order 2023-03-08 00:59:00 -08:00
Leijurv
19eda1bfe5 scaffolder output 2023-03-07 00:52:39 -08:00
Leijurv
1ffadf0242 refactor out scaffolder strategy 2023-03-07 00:37:53 -08:00
Leijurv
5d0904b46e refactor dependencygraphscaffoldingoverlay to be only mutable inside scaffolder (this was bugging me) 2023-03-04 22:00:18 -08:00
William Jacobs
3eda7a57e8 Added assessment of ancestor pointers to optimization_ideas.txt
This adds my assessment of the performance of the ancestor pointers optimization in practice to optimization_ideas.txt.
2022-08-02 19:27:45 -04:00
William Jacobs
2031ed4bc3 Added ancestor pointers to optimization_ideas.txt
This adds the idea of using ancestor pointers to optimization_ideas.txt.
2022-07-19 12:12:57 -04:00
Leijurv
a448d97ec9 dont remember, misc changes 2021-11-01 17:41:29 -07:00
Leijurv
1a59427957 refactor out sneak position 2021-09-03 13:47:00 -07:00
Leijurv
217f6ecf28 refactor out zobrist world state cache 2021-09-03 13:29:29 -07:00
Leijurv
0fd91edb97 column system, sneaking nodes, connected up raytrace system, misc refactors 2021-09-01 16:22:59 -07:00
Leijurv
35c2d8ba24 refactors and begin on sneak nodes 2021-08-31 17:40:01 -07:00
Leijurv
b26d10e26e jump physics 2021-08-27 23:56:46 -07:00
Leijurv
9da3e09062 snow sucks 2021-08-27 19:01:31 -07:00
Leijurv
9fce9ef5e3 precompute scaffolding variants to remove branch in dependency graph lookup 2021-08-27 16:13:29 -07:00
Leijurv
e5773da108 that's what the mask is 2021-08-24 22:21:41 -07:00
Leijurv
554c0de188 misc progress hooking everything up into solver engine harness 2021-08-24 20:26:38 -07:00
Leijurv
bea31fe77d Merge branch 'master' into builder-2 2021-08-24 15:16:30 -07:00
Leijurv
bcd22dc91c debug 2021-08-24 10:51:38 -07:00
Leijurv
33082428f3 some progress and reworking of greedy solver 2021-08-24 00:17:55 -07:00
Leijurv
0b4e5f753a tweaked physics and begun core pathfinder loop 2021-08-20 16:27:36 -07:00
Leijurv
5aa0dfc98c started on greedy solver, using concept from the zobrist testing 2021-08-19 00:16:52 -07:00
Leijurv
164d0e07cd bounds refactor and start on solver engine interface 2021-08-18 21:50:41 -07:00
Leijurv
b608a8a1e0 misc 2021-08-17 16:04:23 -07:00
Leijurv
13d0e2a5bf Merge pull request #2879 from scorbett123/fixProguard
Fix proguard from being broken.
2021-07-18 23:29:56 -07:00
scorbett123
c3085ae34f Fix proguard
Signed-off-by: scorbett123 <50634068+scorbett123@users.noreply.github.com>
2021-07-18 18:37:20 +01:00
Leijurv
ce2ec8047e Merge pull request #2825 from Zephreo/parkour-place
ParkourPlace for shorter parkour jumps
2021-07-16 20:50:23 -07:00
Harry
335cb7016e fix verifiedMaxJump
- remove redundant assignment by changing some values
- testing Co-Authors

Co-Authored-By: Leijurv <leijurv@gmail.com>
2021-07-17 13:28:12 +10:00
Harry
7a7b050615 weird verifiedMaxJump 2021-07-17 12:34:58 +10:00
Leijurv
6ff7ae800a Merge pull request #2833 from ZacSharp/layerHeight
 Add layerHeight setting
2021-07-16 18:47:15 -07:00
Harry
2159773723 requested changes
- tabs changed to 4 spaces
- fixed checking if block place is behind player
2021-07-01 10:09:06 +10:00
ZacSharp
ab3a015d61 Add layerHeight setting 2021-06-24 23:33:48 +02:00
Harry
3142387e45 Fix collision early return
not tested yet
- fixes early returns
2021-06-23 06:25:10 +10:00
Harry
051325e10f allow smaller parkour place jumps
allows 2 and 1 block parkour place jumps
2021-06-21 10:58:11 +10:00
Harry
199d5d57d5 Update .gitignore 2021-06-21 09:49:18 +10:00
Leijurv
b96795c517 Merge pull request #2803 from scorbett123/farmInventory
Make farm use inventory when allowInventory is enabled.
2021-06-14 12:32:53 -10:00
scorbett123
64ba96daf2 Do edit suggested by leijurv 2021-06-14 20:44:32 +01:00
Leijurv
14b17d86e5 Merge pull request #2801 from scorbett123/master
Add github actions.
2021-06-13 10:21:51 -10:00
Leijurv
90d5f27026 Merge pull request #2804 from ZacSharp/selCopyPaste
 Add a clipboard to #sel
2021-06-13 10:21:10 -10:00
Leijurv
16386b8ddc Merge pull request #2796 from mankool0/itemSaverThreshold
Added itemSaverThreshold setting
2021-06-13 10:17:28 -10:00
Leijurv
cbef21b9ad Merge pull request #2800 from scorbett123/patch-3
Remove broken hit count badge
2021-06-13 10:16:51 -10:00
ZacSharp
cec44e3668 Add a clipboard to #sel 2021-06-13 00:21:52 +02:00
scorbett123
f09f1e7f85 Make farm use inventory when allowInventory is enabled. 2021-06-12 18:18:56 +01:00
scorbett123
95910bc6cb Cleanup - travis.org is now deprecated and can no longer be used. 2021-06-12 14:13:39 +01:00
scorbett123
cc488ccff0 Make actions run tests as well. 2021-06-12 14:09:50 +01:00
scorbett123
37e129bfb9 Create run_tests.yml 2021-06-12 14:08:04 +01:00
scorbett123
6adc923bcb Revert "update mapping.txt location"
This reverts commit 065470ce

Github doesn't seem to support ../
2021-06-12 14:07:35 +01:00
scorbett123
065470cecb update mapping.txt location 2021-06-12 14:02:31 +01:00
scorbett123
260989bda6 Update build java version for github actions. 2021-06-12 13:52:56 +01:00
scorbett123
64b6e0fd56 Remove broken hit count badge 2021-06-12 13:49:59 +01:00
scorbett123
8f45718b75 Try to create github actions
An attempt at github actions.
2021-06-12 11:27:27 +01:00
scorbett123
e66bb7a14b Make proguard output the mapping. 2021-06-12 11:14:59 +01:00
mankool
8bfe32eeef Added itemSaverThreshold 2021-06-09 10:34:45 -07:00
Leijurv
e85c1bbc0d Merge pull request #2736 from ZacSharp/exploreForBlocksForMining
Make MineProcess respect exploreForBlocks
2021-05-28 13:27:13 -07:00
ZacSharp
f99bf0d000 Make legitMode always explore 2021-05-28 22:18:33 +02:00
Leijurv
db24a2251f Merge pull request #2771 from ZacSharp/notificationCallback
More log callbacks
2021-05-26 11:32:53 -07:00
Leijurv
fcb3747690 Merge pull request #2776 from thecakeisalie25/master
Add "RenderGoalAsBox" Setting
2021-05-26 11:30:51 -07:00
Tabbs
dcc27a7447 oops forgot the javadoc 2021-05-25 14:52:16 -05:00
Tabbs
bea39bc613 Merge branch 'master' of https://github.com/thecakeisalie25/baritone 2021-05-25 14:44:59 -05:00
Tabbs
546493ba45 do our best to stop beacon animating
The game seems to animate the beacons anyway, so it does shake a little bit.
2021-05-25 14:44:54 -05:00
Tabbs
dda4928693 change name to renderGoalAnimated 2021-05-25 14:43:32 -05:00
Larson
7d144dd076 fix decimal
Co-authored-by: scorbett123 <50634068+scorbett123@users.noreply.github.com>
2021-05-25 14:33:13 -05:00
Tabbs
73e0700ea3 fix weird rendering issue 2021-05-25 12:41:36 -05:00
Tabbs
3fc36cf798 fix y to 1 if animation is disabled 2021-05-25 12:34:17 -05:00
Leijurv
02f5d4efbe misc bounds benchmark, property extractor, scaffolder 2021-05-24 17:16:25 -07:00
Leijurv
a9b7b91a3c misc tweaks, forgot to commit last week 2021-05-24 12:52:34 -07:00
ZacSharp
dbc43b445b Replace unhandled exception with a helpful message 2021-05-24 03:38:14 +02:00
ZacSharp
638fcd393a Don't try to tab complete hidden settings 2021-05-24 03:20:31 +02:00
ZacSharp
7b5f419713 Treat the new callbacks like the old one 2021-05-24 03:14:33 +02:00
Leijurv
d501359857 progress on properties and entity oriented blocks 2021-05-18 00:16:30 -07:00
Leijurv
d9591e089d basic impl of place options 2021-05-17 02:12:51 -07:00
Leijurv
4848e901c9 progress on reachability cache and raytracer tweaks 2021-05-17 01:53:16 -07:00
Leijurv
65a650c1a6 readme 2021-05-15 22:30:51 -07:00
Leijurv
ca2e7c958a remove zoomy branchy 2021-05-15 21:41:47 -07:00
Leijurv
c97b089c61 rework placeagainstdata 2021-05-13 00:37:40 -07:00
Leijurv
5170b34962 blip 2021-05-12 01:10:25 -07:00
Leijurv
0a8b6e9427 many more blocks, physics attempt 2021-05-11 23:27:52 -07:00
ZacSharp
253fbad3db Make MineProcess respect exploreForBlocks 2021-05-10 22:37:35 +02:00
Leijurv
efb0afcd6c switch to builder pattern for block state cached data 2021-05-10 02:18:59 -07:00
Leijurv
5c85d0cfd1 fixed up raytracer and placement option 2021-05-10 00:23:10 -07:00
ZacSharp
522de3d4b7 Add callback settings for toast pop-ups and desktop notifications 2021-05-10 00:31:37 +02:00
ZacSharp
dc9ae67657 Move NotificationHelper to api and give Helper some methods for notifications 2021-05-10 00:26:33 +02:00
Leijurv
fdf899eabf progress on raytracer 2021-04-21 11:42:56 -07:00
Leijurv
fccac8ed74 Merge pull request #2664 from ZacSharp/buildSelectedSchematic
Add setting to only build selected part of schematica schematic
2021-04-20 23:27:57 -07:00
Leijurv
24c895084e Merge pull request #2647 from scorbett123/patch-2
switch from forge mods to just other mods.
2021-04-20 23:15:37 -07:00
Leijurv
16fbfdecb5 Merge pull request #2645 from millennIumAMbiguity/patch-1
Added missing information to USAGE.md
2021-04-20 23:15:25 -07:00
Leijurv
b79e281074 Merge pull request #2635 from ZacSharp/autoTool
Invert disableAutoTool to autoTool
2021-04-20 23:15:10 -07:00
Leijurv
93ac380fd6 Merge pull request #2634 from ZacSharp/patch-2
fix typo
2021-04-20 23:13:57 -07:00
Leijurv
e62f480836 started on scaffolding 2021-04-16 20:43:24 -07:00
ZacSharp
46066d4cac Misc
* Rename schematicaOnlyBuildSelection to buildOnlySelection
* Make it useable with #build as well
* remove debugging code I forgot
2021-04-14 23:36:16 +02:00
Leijurv
6ef6651ed6 more optim 2021-04-13 19:08:44 -07:00
Leijurv
21aaab1b9e optims 2021-04-13 18:03:33 -07:00
Leijurv
8450675401 saving progress here, incremental scaffolding works and is fast 2021-04-13 16:08:30 -07:00
ZacSharp
c13cf4f29c Add setting to only build selected part of schematica schematic 2021-04-13 23:09:54 +02:00
ZacSharp
a4f06a9e1e Update javadoc as well 2021-04-10 23:56:30 +02:00
scorbett123
cbc5fc8d08 switch from forge mods to just other mods. 2021-04-08 18:36:46 +01:00
millennIumAMbiguity
0a27c0b6e4 Added missing information to USAGE.md
Added missing information about the `farm` command.
2021-04-07 18:12:47 +02:00
ZacSharp
f348a20035 invert disableAutoTool to autoTool 2021-04-04 03:34:10 +02:00
ZacSharp
bdb98b487f fix typo 2021-04-04 03:17:35 +02:00
Leijurv
2cb6402189 Update README.md 2021-04-03 16:56:26 -07:00
Leijurv
861bb7a00a v1.2.15 2021-04-03 16:50:01 -07:00
Leijurv
43d5458a25 fix weird behavior where allowBreak false broke #goto 2021-04-03 16:41:45 -07:00
Leijurv
96fd72e5b0 testing 2021-04-03 15:49:30 -07:00
Leijurv
fe491e4a7d Merge pull request #1809 from Moondarker/master
Added "install" target for instant maven-ready releases
2021-04-03 13:40:56 -07:00
Leijurv
c1794dd0ca reduce useless links 2021-03-25 10:41:16 -10:00
Leijurv
8f7d8b1cba Merge pull request #2611 from Flurrrr/master
Center badges and other stuff
2021-03-25 09:29:08 -10:00
flurr
8ebb8a04fa Center badges and other stuff
-center the badges
-re-arrange them to be more organized
-update the Aristois/Impact badges to the correct versions and fix broken link
2021-03-25 11:51:18 -07:00
Leijurv
ef6435a02a whatever i don't care 2021-03-23 22:44:20 -10:00
Leijurv
5cbe0a8230 Update README.md 2021-03-23 22:44:03 -10:00
Leijurv
dcef6b556c Update README.md 2021-03-23 22:42:39 -10:00
Leijurv
c07a636db2 Update README.md 2021-03-23 22:41:59 -10:00
Leijurv
a6be95fe33 Merge pull request #2606 from scorbett123/patch-1
fix typo
2021-03-23 10:19:11 -10:00
scorbett123
14149aa6b1 fix typo 2021-03-23 19:35:11 +00:00
Leijurv
ae901219fb Merge pull request #2526 from ZacSharp/buildSkipBlocks
Settings to alter block treatment while builing
2021-03-23 08:09:44 -10:00
Leijurv
6d9600d132 Update README.md 2021-03-21 13:59:00 -07:00
Leijurv
ccc55562cd Update README.md 2021-03-21 13:52:27 -07:00
ZacSharp
67d9ae881f don't allocate tons of empty lists 2021-03-09 12:31:02 +01:00
ZacSharp
61e0525ee8 Don't copy block state properties every time 2021-03-09 12:26:47 +01:00
ZacSharp
363519db02 treat all airs as air 2021-03-09 11:53:43 +01:00
Leijurv
4bc179bd2a Merge pull request #2462 from scorbett123/ModifiedImprovement
Improve #modified command to include original setting value.
2021-02-19 20:14:35 -08:00
Leijurv
76debda76e Merge pull request #1978 from ZacSharp/master
 Add improved ETA and a command to access it
2021-02-19 20:13:47 -08:00
Leijurv
b4eabe19cb Merge pull request #2482 from ZacSharp/schematicCacheClearing
Clear caches of schematics when moving them
2021-02-19 16:06:28 -08:00
ZacSharp
971b75860f Call reset() on static schematics as well 2021-02-19 23:57:33 +01:00
ZacSharp
5a926bf169 formatting 2021-02-19 23:52:18 +01:00
Leijurv
d34f37c563 Merge pull request #2476 from biscuut/patch-1
Fixed incorrect block pos world coordinates
2021-02-19 10:54:47 -08:00
Leijurv
6035a01019 Merge pull request #2481 from ZacSharp/buildRepeatCrash
Don't crash by buildRepeating too often
2021-02-19 10:49:06 -08:00
ZacSharp
c880f71dc8 Clear caches of schematics when moving them 2021-02-17 01:59:23 +01:00
ZacSharp
13422ef7ce lag > crash 2021-02-17 01:19:16 +01:00
Biscuit
84e2efd42c Fixed incorrect block pos world coordinates
Fix block pos being incorrect when converting chunk coordinates to world coordinates because of order of operations.
2021-02-15 14:21:03 -05:00
ZacSharp
113d26937d remove unused imports 2021-02-11 01:08:33 +01:00
ZacSharp
34606415d7 Don't mark skipped blocks as invalid just because they are far away 2021-02-10 23:45:12 +01:00
scorbett123
6b9c1f0a22 Improve #modified command to include original setting value.
Signed-off-by: scorbett123 <50634068+scorbett123@users.noreply.github.com>
2021-02-10 16:00:44 +00:00
ZacSharp
132cc0e131 make range initialization more readable 2021-02-10 10:25:17 +01:00
ZacSharp
5926369a56 formatting and comments 2021-02-10 10:15:14 +01:00
ZacSharp
ff068d374f Don't box doubles 2021-02-10 00:29:45 +01:00
Leijurv
4132d6ff61 Merge pull request #2138 from scorbett123/swordSaver
add useSwordToMine setting.
2021-02-08 16:54:37 -08:00
scorbett123
1f10199e64 Change use sword to mine to default to true.
Signed-off-by: scorbett123 <50634068+scorbett123@users.noreply.github.com>
2021-02-08 08:34:31 +00:00
Leijurv
e97704b37f Merge pull request #2139 from scorbett123/notifyOnDeath
notify users that their death position has been saved.
2021-02-07 14:32:43 -08:00
scorbett123
4ae81a3b0b Merge branch 'master' into swordSaver 2021-02-07 12:19:18 +00:00
Moondarker
f4ec9a8ec1 Merge pull request #2 from cabaletta/master
Fetching latest updates
2021-02-07 06:39:00 +03:00
Leijurv
711037b619 rearrange for consistency 2021-02-06 13:36:24 -08:00
Leijurv
b32c9f1724 Merge pull request #2107 from scorbett123/toolsSaver
add itemSaver setting.
2021-02-06 13:33:01 -08:00
Leijurv
be132c531e Update SETUP.md 2021-02-05 22:53:44 -08:00
Leijurv
fb8826caf4 Update README.md 2021-02-05 22:42:03 -08:00
Leijurv
adff60b118 Update README.md 2021-02-05 22:41:52 -08:00
Leijurv
8f863bf19b empty 2021-02-05 20:08:46 -08:00
Leijurv
331a7f3842 Merge pull request #2407 from DifferentPerson/master
Fix SpongePowered Maven repo URL
2021-02-02 16:06:48 -08:00
DifferentPerson
25de16e051 Fix SpongePowered Maven repo URL
SpongePowered recently changed their Maven repo URL, so this is the right one
2021-01-31 15:55:52 -08:00
Leijurv
a732e766f4 crucial performance optimization 2021-01-30 17:22:19 -08:00
Leijurv
91854f97ad fully remove remnants of xvfb 2021-01-29 21:12:44 -08:00
Leijurv
835fb3471f a long overdue reformat of every file 2021-01-29 20:17:53 -08:00
Leijurv
a9f497981f Merge pull request #2080 from millennIumAMbiguity/master
Added range argument to farm
2021-01-29 17:41:08 -08:00
Leijurv
74dd88d123 Merge pull request #2359 from stragulus/build-with-forge-instructions
Add instructions to build with forge for minecraft 1.15+
2021-01-29 17:37:43 -08:00
ZacSharp
fd61207709 Fix heuristic(no args) returning wrong values 2021-01-28 01:40:33 +01:00
Leijurv
b94494d386 Merge pull request #2357 from ZacSharp/builderMaterialLogging
Log blocks the builder can't place (missing or obstructed by flowing liquid) when failing
2021-01-26 23:28:45 -08:00
Leijurv
974b19fcc7 Merge pull request #2378 from ZacSharp/patch-1
Correct usage for mining a specific amount
2021-01-26 23:24:07 -08:00
ZacSharp
364b7b5438 Correct usage for mining a specific amount
Found and fixed by @CesiumCs
2021-01-21 15:39:37 +01:00
ZacSharp
8c1a9f460d Simple blockstate preservation for buildSubstitutes 2021-01-18 12:06:50 +01:00
ZacSharp
f6d4a315c7 Remove debug log 2021-01-18 11:58:42 +01:00
Bram Avontuur
0222c47113 Typo fix 2021-01-17 11:40:52 -05:00
ZacSharp
fc1a2a6112 Add buildSubstitutes setting to builder 2021-01-17 02:45:40 +01:00
ZacSharp
13547781d2 add buildValidSubstitutes setting to builder 2021-01-17 00:53:50 +01:00
ZacSharp
d375d1abc9 Add setting parser for mappings 2021-01-17 00:16:34 +01:00
Bram Avontuur
33d007eea5 Add instructions to build with forge for minecraft 1.15+ 2021-01-16 11:34:12 -05:00
ZacSharp
5e4f31f39e proper place/break costs for skipped blocks 2021-01-16 02:05:59 +01:00
ZacSharp
79e0f4ba23 Log blocks it can't place 2021-01-15 12:52:38 +01:00
ZacSharp
dba186347c remove likely useless code breaking buildSkipBlocks 2021-01-13 22:45:59 +01:00
ZacSharp
7988274d61 add buildSkipBlocks setting 2021-01-12 23:59:11 +01:00
Leijurv
72cf9392b1 Update README.md 2020-12-24 21:34:02 -08:00
Leijurv
b6265036d4 Update README.md 2020-12-24 21:33:29 -08:00
Leijurv
dc70d810c9 Update README.md 2020-12-24 21:33:11 -08:00
Leijurv
16cfcb36a3 Update USAGE.md 2020-11-29 20:04:44 -08:00
Leijurv
6bec994a57 Merge pull request #2185 from unrootexe/master
Update rootNET's supported version
2020-11-19 23:56:45 -08:00
unrootexe
a99206b6c2 Update rootNET's supported version
rootNET supports the latest version of Baritone, this change reflects that
2020-11-16 17:18:32 +00:00
Leijurv
c491d67925 add setting to just skip layers that the builder fails to construct 2020-11-11 17:53:26 -08:00
Sam Corbett
b9eeab06a1 change useSwordToMine to default to false.
Signed-off-by: Sam Corbett <sam@corbettchocolates.com>
2020-11-02 07:47:36 +00:00
millennIumAMbiguity
853b5ca771 Moved throw up into the default: 2020-11-02 01:44:12 +01:00
millennIumAMbiguity
f4706fff18 Simplified and optimised code 2020-11-02 01:25:25 +01:00
millennIumAMbiguity
7218a46211 Added defaults and javadocs 2020-11-02 00:33:31 +01:00
scorbett123
c0f7d5ab44 fix error made while copying and pasting.
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-11-01 17:30:53 +00:00
scorbett123
60f81fb89d notify users that their death position has been saved.
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-11-01 17:18:31 +00:00
scorbett123
49bc96dc7e add useSwordToMine setting.
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-11-01 16:12:38 +00:00
Leijurv
320a5d64a3 well i guess technically there could be an ore at bedrock level lmao 2020-10-30 22:39:30 -07:00
Leijurv
b16a8ecf21 Merge pull request #2079 from scorbett123/limitedMineDistance
add a minimum Y level during mining.
2020-10-30 22:35:26 -07:00
Leijurv
73265ef944 Merge pull request #2100 from GameCenterJerry/master
added jdk 8 instructions for macOS in SETUP.md
2020-10-30 22:28:57 -07:00
Leijurv
3bbc141e9a Merge pull request #2132 from ZacSharp/noForgeMod
don't make non-forge jars valid mods (fixes #2124)
2020-10-30 22:28:03 -07:00
ZacSharp
9ca95e8e14 don't make non-forge jars valid mods (fixes #2124) 2020-10-31 03:21:59 +01:00
Sam Corbett
9922382581 don't fall back onto the first slot if it has a low durability item in the slot.
Signed-off-by: Sam Corbett <sam@corbettchocolates.com>
2020-10-28 08:44:40 +00:00
scorbett123
4aa52d2f2e add itemSaver setting.
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-10-24 18:03:29 +01:00
Leijurv
6d51e10090 Merge pull request #1971 from krzys-h/fix-entity-follow-forge
Fix "#entity follow <name>" under Forge
2020-10-23 18:54:11 -07:00
GameCenterJerry
14b75973b0 Update SETUP.md 2020-10-22 15:02:17 +11:00
GameCenterJerry
0bfd0bca0c Update SETUP.md 2020-10-22 13:47:50 +11:00
GameCenterJerry
cafb810a1f Update SETUP.md 2020-10-22 13:28:18 +11:00
GameCenterJerry
07704b3ec7 Update SETUP.md 2020-10-22 13:14:53 +11:00
GameCenterJerry
7032efcc05 added jdk 8 instructions for macOS
added necessary commands and download links
2020-10-22 13:09:56 +11:00
millennIumAMbiguity
65a5677b33 Added the feature to only farm within range of a waypoint. 2020-10-22 00:36:19 +02:00
millennIumAMbiguity
5d3522ca0a Added range argument to farm 2020-10-16 23:32:53 +02:00
Sam Corbett
bfb530e02b add a minimum Y level.
Signed-off-by: Sam Corbett <sam@corbettchocolates.com>
2020-10-16 17:02:02 +01:00
ZacSharp
9393192036 Slight change to heuristic(no args) 2020-10-16 01:30:04 +02:00
btrekkie
5cfefbb9ec Merge pull request #2 from btrekkie/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1
2020-10-15 19:20:39 -04:00
btrekkie
1c8ccd4646 Merge pull request #1 from btrekkie/dependabot/maven/junit-junit-4.13.1
Bump junit from 4.12 to 4.13.1
2020-10-15 19:17:39 -04:00
ZacSharp
3cdbc4cb83 👌formatting in of comments 2020-10-15 21:48:17 +02:00
ZacSharp
0c7741120a 👌formatting 2020-10-15 00:05:54 +02:00
ZacSharp
e529438c7e Don't use Abs on Sqrt 2020-10-14 21:14:17 +02:00
Leijurv
5a5d11922f Merge pull request #1995 from scorbett123/exposedOres
add mineOnlyExposedOres setting
2020-10-14 12:01:49 -07:00
scorbett123
39cfebeb34 fix formatting
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-10-14 20:00:49 +01:00
Leijurv
950f47ccae Merge pull request #1958 from CDAGaming/feature/toasts
 Added Toast API Support
2020-10-14 11:18:09 -07:00
CDAGaming
d2c625e1c9 Apply Review Comments 2020-10-14 13:14:23 -05:00
Leijurv
3f207b7041 Merge pull request #2076 from CDAGaming/feature/rendering-compat-fix
🐛 Fix a Rendering Conflict with some other Mods
2020-10-14 11:09:00 -07:00
Leijurv
8deb9e5a35 Merge pull request #1959 from CDAGaming/feature/top-command
 Added a top/surface command
2020-10-14 11:02:07 -07:00
Leijurv
5eeb33a6f5 Merge pull request #1845 from mariusdkm/master
Fixing crash after clicking into the air using the #click command
2020-10-14 10:59:34 -07:00
dependabot[bot]
6f69316966 Bump junit from 4.12 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 12:15:30 +00:00
dependabot[bot]
5e77ef97e4 Bump junit from 4.12 to 4.13.1
Bumps [junit](https://github.com/junit-team/junit4) from 4.12 to 4.13.1.
- [Release notes](https://github.com/junit-team/junit4/releases)
- [Changelog](https://github.com/junit-team/junit4/blob/main/doc/ReleaseNotes4.12.md)
- [Commits](https://github.com/junit-team/junit4/compare/r4.12...r4.13.1)

Signed-off-by: dependabot[bot] <support@github.com>
2020-10-13 12:15:26 +00:00
CDAGaming
918f009e8a 🐛 Fix a Rendering Conflict with some other Mods
In testing within Fabritone, it was found that these two lines (Which were previously used for an unknown optifine workaround) are no longer needed, and had no known side effects as of writing.

This can be backported as needed, but details are unknown how far this can go down

Future me PS: This PR is a superseed of my last one, erased during repo refactors, so now it lives on master branch. Testing recommended and can be up-ported/down-ported as you wish.
2020-10-12 12:52:05 -05:00
CDAGaming
d6665f1cd5 Added Toast API Support
This adds in a logAsToast and toastTimer option, and is a minified form of Indrit's initial implementation previously used from fabritone
2020-10-12 12:46:01 -05:00
CDAGaming
af29ed7146 Added a top/surface command
Superseeds PR #594
2020-10-12 12:44:12 -05:00
Leijurv
8ddc795158 Merge pull request #2020 from ZacSharp/wpgoto
make `#wp goto` behave like `#wp goal` and `#path`
2020-09-29 16:55:50 -07:00
ZacSharp
8a572516fc Update description of WaypointsCommand 2020-09-23 22:54:41 +02:00
ZacSharp
aebfbba20e Also override heuristic(no args) when overriding isInGoal() 2020-09-20 22:39:48 +02:00
ZacSharp
85cc86346c Actually use Y and Z bounds for Y and Z 2020-09-20 22:20:24 +02:00
ZacSharp
b20e095683 add heuristic(no args) to GoalNear and GoalRunAway
not really a good solution but better than nothing
2020-09-20 00:29:31 +02:00
ZacSharp
b4d7f05165 🐛 fix two NPEs in estimatedTickToGoal
apparently `ctx.playerFeet()` and `startPosition` can be `null` before pathing the first time
2020-09-19 21:46:07 +02:00
ZacSharp
46a12754e9 🐛Reset ETA and return 0 if we are already there
not doing this caused a continuously increasing ETA when standing inside a `GoalNear` from `FollowProcess`
2020-09-19 00:30:25 +02:00
ZacSharp
411b2a0acc 🔨move ETA reset to it's own function 2020-09-18 23:58:06 +02:00
ZacSharp
508dacac63 directly start pathing after #home
just like servers directly teleport you after `/home` without waiting for something like `/teleport`
2020-09-18 22:41:33 +02:00
ZacSharp
13ca691f5d make #wp goto behave like #goto
It now is a combined `#wp goal` and `#path` just like `#goto` is `#goal` and `#path`
2020-09-16 20:19:55 +02:00
Leijurv
7e4d2c9b28 Update README.md 2020-09-15 12:43:34 -07:00
Brady
500c34c330 Merge pull request #2015 from babbaj/fix-troll-code
Don't call onLostControl on processes that haven't been fully constructed
2020-09-13 17:46:23 -05:00
Babbaj
234fd3f75e don't use getter 2020-09-13 18:45:50 -04:00
Babbaj
32ef30686b Don't call onLostControl on processes that haven't been fully constructed 2020-09-13 18:21:22 -04:00
Leijurv
175df6ce7a Update USAGE.md 2020-09-11 21:54:20 -07:00
Leijurv
96b874c099 Update README.md 2020-09-11 21:52:43 -07:00
Sam Corbett
612510550f fix javadoc.
Signed-off-by: Sam Corbett <sam@corbettchocolates.com>
2020-09-08 19:00:41 +01:00
Sam Corbett
80e4852f90 Merge https://github.com/cabaletta/baritone into exposedOres 2020-09-08 17:48:45 +01:00
Sam Corbett
071243b99a move is transparent to movement helper and circle maker 2020-09-08 17:47:46 +01:00
Sam Corbett
547db3a6b4 make the ability to turn it off.
Signed-off-by: Sam Corbett <sam@corbettchocolates.com>
2020-09-08 17:47:45 +01:00
scorbett123
063f698bd2 need to remove diagonals, however this does most of what you suggest.
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-09-08 17:47:45 +01:00
scorbett123
bcbfca100f add mineOnlyExposedOres setting
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-09-08 17:47:45 +01:00
Leijurv
8206b1673c Merge pull request #1988 from scorbett123/patch1
fix typo in java-doc x2
2020-09-07 13:18:52 -07:00
ZacSharp
7255ccbdaa add heuristic(no args) to GoalComposite
GoalNear and GoalRunAway are still missing it
2020-09-06 16:42:05 +02:00
ZacSharp
45dc8b949d add a method to get the heuristic at the goal
this alows the ETA to work with goals not ending with a heuristic of 0

GoalComposite, GoalRunAway and GoalNear are still missing
2020-09-05 22:32:38 +02:00
ZacSharp
10e3a5afc4 negative ETAs are actually impossible now 2020-09-05 22:13:05 +02:00
ZacSharp
303aa79ffb Update ETA formula, assuming heuritic at goal is 0 2020-09-04 23:56:01 +02:00
ZacSharp
35f3be9296 get rid of negative ETAs the lazy way 2020-09-02 22:59:13 +02:00
scorbett123
d7088c8eea fix typo in java-doc x2
Signed-off-by: scorbett123 <sam@corbettchocolates.com>
2020-08-31 18:48:46 +01:00
ZacSharp
695954bdb0 no eta after 0 ticks or with division by 0 2020-08-28 23:37:23 +02:00
ZacSharp
d29b3ee893 Fix copy/paste mistake in ETACommand.getLongDesc() 2020-08-28 01:19:06 +02:00
ZacSharp
d9cecb35cb rename Eta to ETA 2020-08-28 00:56:18 +02:00
ZacSharp
71dd6c6333 👌formatting 2020-08-27 01:16:17 +02:00
ZacSharp
56f13d314a Add eta command 2020-08-26 23:53:02 +02:00
ZacSharp
b628d67961 Add ETA for full path 2020-08-26 23:52:44 +02:00
Leijurv
bf723deced Merge pull request #1964 from ZacSharp/master
Fix MovementDiagonal being safeToCancel while cornering over air 2.0
2020-08-24 16:20:01 -07:00
ZacSharp
9636e69a6b slightly better condition 2020-08-24 23:06:19 +02:00
krzys-h
ed91e2aa7b Fix "#entity follow <name>" under Forge
One of the Forge patches removes EntityList.REGISTRY and provides
the getClass method as a replacement.

The fix is based on a similar one I found in WorldDownloader

Closes #1376 (and duplicates: #1777 and #1815)
2020-08-24 22:24:18 +02:00
ZacSharp
3c691bb498 But now it's working 2020-08-20 23:33:47 +02:00
ZacSharp
ea35a3478f Codacity again for the same and syntax
dab
2020-08-20 23:16:59 +02:00
ZacSharp
b7d1ba1fa5 Make Codacity happy 2020-08-20 23:11:55 +02:00
ZacSharp
5f686c1c12 improve isSafeToCancel in MovementDiagonal even more
It did not return true early enough for backfill while cornering over air
2020-08-20 22:55:42 +02:00
Leijurv
4eea8308d7 Merge pull request #1956 from RealIndrit/patch-1
🔥 Get yeeted unused code
2020-08-18 11:14:25 -07:00
kuthy
7f9704592e Made catch function wide 2020-08-18 15:40:12 +02:00
RealIndrit
523f13c430 🔥 Get yeeted unused code
Removed an unused function that can't be used anyways, because RayTraceUtils cant detect entity hit...
2020-08-18 12:36:10 +02:00
Leijurv
1c8079c051 Merge pull request #1058 from ADShenoi/patch-1
The grammar mistakes were corrected
2020-08-17 16:40:56 -07:00
Leijurv
2abd024b3c Merge branch 'master' into patch-1 2020-08-17 16:40:41 -07:00
Leijurv
7992b63aae Merge pull request #1346 from aUniqueUser/master
Make desktop notifications more useful
2020-08-17 16:38:36 -07:00
Leijurv
836ef3328c Merge pull request #1541 from babbaj/keep-annotation
Annotation for proguard -keep
2020-08-17 16:36:48 -07:00
Leijurv
c470dc1a17 Merge pull request #1158 from c0nn3r/master
Create .gitmessage
2020-08-17 16:33:48 -07:00
Leijurv
97a1029a72 Merge pull request #1554 from ByteZ1337/master
Fixed Typo
2020-08-17 16:17:47 -07:00
Leijurv
5f9602796a Merge pull request #1876 from CorruptedSeal/master
Update ExecutionControlCommands.java
2020-08-17 16:17:01 -07:00
Leijurv
02e7886e77 properly set isSafeToCancel in MovementDiagonal, fixes #1788 2020-08-17 16:15:56 -07:00
Leijurv
9851623557 anti-indrit-cringe 2020-08-17 16:03:04 -07:00
Leijurv
f0d2bae3d1 Merge pull request #1947 from RealIndrit/master
Add auto tool setting
2020-08-17 15:57:37 -07:00
Leijurv
f3561cab47 SUPER cute code for repackOnAnyBlockChange 2020-08-17 15:54:42 -07:00
Leijurv
38d047dbd1 make the packer queue super cute and deduplicated 2020-08-17 15:19:11 -07:00
Leijurv
e6ba4ef309 we don't compile here 2020-08-17 15:00:57 -07:00
Leijurv
460833f7d6 Merge branch 'master' of github.com:cabaletta/baritone 2020-08-17 14:59:20 -07:00
RealIndrit
2eba22031a Maybe dont have ignore cost calculation override auto tool? 2020-08-14 22:47:39 +02:00
RealIndrit
ac55de63e9 Maybe dont have ignore cost calculation override auto tool? 2020-08-14 17:55:10 +02:00
RealIndrit
88e2fba447 Ok, Im actually retarded 2020-08-14 17:11:31 +02:00
RealIndrit
94ac15a8fc KEK False != True :clown: 2020-08-14 17:06:41 +02:00
RealIndrit
19355cb4f2 Added AutoToolMovement bypass setting for special usage cases, should not be used it not actually necessary 2020-08-14 10:58:15 +02:00
RealIndrit
e0ff16e2dd Nice brainfart 2020-08-14 10:34:21 +02:00
RealIndrit
49db52673a Lol 2020-08-14 10:25:51 +02:00
RealIndrit
f8872e1cd4 Everything can be traced back to getBestSlot(); 2020-08-14 10:14:02 +02:00
RealIndrit
2ed3e10833 And we try this again, because wtf?? 2020-08-13 23:20:30 +02:00
RealIndrit
2b6fe188ed Why calculate stuff that isnt needed... 2020-08-13 22:47:40 +02:00
RealIndrit
2ddc2c3660 Add auto tool settings because 2 lines of code lols 2020-08-13 22:36:34 +02:00
Leijurv
b187d86074 fix orsond rock brain moment 2020-08-05 23:31:32 -07:00
Leijurv
727694fdd5 Merge pull request #1939 from orsondmc/startAtLayer
Introduce startAtLayer
2020-08-05 23:28:52 -07:00
orsondmc
7081cf7172 Introduce startAtLayer to start building at a specific layer in the schematic. To be used only with buildWithLayers true. 2020-08-06 16:23:13 +10:00
Leijurv
a25afd5c13 Merge pull request #1895 from John200410/patch-1
add rusherhack integration badge
2020-07-29 12:57:41 -07:00
Leijurv
c180eb9975 Update README.md 2020-07-29 12:52:19 -07:00
Leijurv
9e45998a65 brady shouldn't merge PRs that don't compile, thanks cdagaming 2020-07-26 13:21:51 -07:00
John
2acf64a0d0 add rusherhack integration badge
as of rusherhack v1.0 there is baritone API integration, similar to future's.
2020-07-20 03:12:24 -04:00
Brady
9d41367eff Merge pull request #1873 from CorruptedSeal/master
Update ProguardTask.java
2020-07-20 00:59:52 -05:00
Leijurv
b64dd8f25f Merge pull request #1879 from elonmusksama/master
updated compatible versions to future badge
2020-07-16 21:12:13 -07:00
elongated muskrat
cbb3483456 updated compatible versions to future badge
updated the compatible versions to the future integrations badge
2020-07-16 14:35:17 -03:00
CorruptedSeal
6603e8b11e Update ExecutionControlCommands.java 2020-07-16 03:45:23 -06:00
CorruptedSeal
d522f9dfa3 Update ProguardTask.java 2020-07-15 01:34:19 -06:00
CorruptedSeal
f02476ff3a Update ProguardTask.java 2020-07-15 01:18:01 -06:00
Leijurv
eafca1e1fe yourkit 2020-07-06 17:07:59 -07:00
kuthy
0055a059f7 Formated Code 2020-07-03 16:52:03 +02:00
kuthy
8262909063 Fixing crash after clicking into the air 2020-07-03 15:36:44 +02:00
Leijurv
e42c19bfec thebes uwu 2020-06-27 22:25:47 -07:00
William Jacobs
0fed0d4371 Removed outdated pointer to documentation
This removes the suggestion to check the source code for the documentation from README.md. Now that there is a website with the documentation, there is no need to look through the source code.
2020-06-26 10:51:11 -04:00
Moondarker
8fe05c9119 fixup! Allow multi-artifact building for Jitpack and local Maven repos 2020-06-20 23:16:20 +03:00
Moondarker
e8e6a9bc5c Allow multi-artifact building for Jitpack and local Maven repos 2020-06-20 23:11:16 +03:00
ByteZ1337
c41eb4afa0 Merge remote-tracking branch 'upstream/master' 2020-06-08 17:42:05 +02:00
Leijurv
80c8294f5f maintain obscenely obvious pro impact bias in subconscious coloring 2020-06-04 11:32:20 -07:00
Leijurv
fc58673abd Merge pull request #1709 from dominikaaaa/patch-1
Added blue badge to integrations badges
2020-06-04 11:31:28 -07:00
William Jacobs
1069dc9700 Increased minimum Java version and updated documentation
This increases the minimum Java version to 7.0, because Maven doesn't like Java 6.0, and it makes assorted improvements to the documentation.
2020-05-30 10:36:45 -04:00
William Jacobs
515a28dcfd Added reference to documentation webpage
This changes README.md to refer to the webpage containing the documentation for the project.
2020-05-30 10:33:13 -04:00
Dominika
ca831bc734 Added blue badge to integrations badges 2020-05-18 13:47:57 -04:00
Leijurv
a76cf0fe9a brady more like brainletdy 2020-05-17 18:35:41 -07:00
Leijurv
688853c523 Merge pull request #1657 from babbaj/rename
bring back ExampleBaritoneControl
2020-05-03 22:24:45 -07:00
Babbaj
806dc8f017 This had to be done 2020-05-04 01:15:18 -04:00
Leijurv
89ab78a329 Update README.md 2020-05-03 18:51:21 -07:00
Leijurv
3a7cb5e020 Merge pull request #1629 from dominikaaaa/patch-1
Fix broken API Settings link in USAGE. Close #1040
2020-04-27 16:59:56 -07:00
Leijurv
d0f594065d Update README.md 2020-04-26 13:22:55 -07:00
Dominika
10677040e0 Fix broken API Settings link in USAGE. Close #1040 2020-04-26 15:22:24 -04:00
Leijurv
c2624bbaaf Update README.md 2020-04-21 13:32:47 -07:00
Leijurv
33d4dd47bb v1.2.14 2020-04-21 12:02:07 -07:00
Leijurv
ec92ab8b39 Update README.md 2020-04-18 22:07:18 -07:00
ByteZ1337
ff3234fcdd Fixed Typo
Fixed Typo in the Long Description of the Goto Command
2020-04-13 20:39:56 +02:00
Babbaj
c32652394e Annotation for proguard -keep 2020-04-12 03:01:24 -04:00
Leijurv
580ba60762 Merge pull request #1344 from dominikaaaa/fix/setupmd
Change 1.14 to 1.15 in SETUP.md
2020-04-09 14:02:28 -07:00
Dominika
0e7bf25de7 fix setup.md as per leij's recommendations 2020-04-09 17:01:26 -04:00
Leijurv
e218ced2c7 i hate myself 2020-03-30 22:23:43 -07:00
Leijurv
3cc4c0ea98 Revert "Update README.md"
This reverts commit ac2a88d186.
2020-03-25 21:52:42 -07:00
Leijurv
ac2a88d186 Update README.md 2020-03-25 21:50:12 -07:00
Leijurv
dff92beea1 v1.2.13 2020-03-25 17:17:10 -07:00
Leijurv
62b808ad48 nickhasbugs 2020-03-18 19:15:47 -07:00
Leijurv
69e871eaad we can copy from this image sure 2020-03-14 12:19:39 -07:00
Leijurv
d759c676f7 disable broken code 2020-03-14 12:13:45 -07:00
Leijurv
12481cc491 v1.2.12 2020-03-14 12:09:35 -07:00
Leijurv
43f11aaf0c finally update usage to furry code 2020-03-14 12:09:19 -07:00
Leijurv
f4842aa512 fix actual underlying sneak issue 2020-03-14 11:51:26 -07:00
Leijurv
bcd3fd3266 Merge pull request #1401 from S-B99/patch-1
Add modified settings to bug template
2020-03-14 10:59:39 -07:00
Bella Who
67256c17cf Add modified settings to bug template 2020-03-14 12:10:26 -04:00
Bella Who
d6106a44f7 Remove dropbox link as 1.15.2 is now officially released 2020-03-13 09:00:17 -04:00
Brady
eda1820773 Fix Cubecraft Crash (Affects 1.13.2+) 2020-03-07 20:17:53 -06:00
Brady
c8856cfea4 Fix #1250 2020-03-07 17:34:27 -06:00
Leijurv
217e0da4a6 Merge pull request #1340 from fw4hre0xxq/issue-1339-trapchest-pathing
fix #1339
2020-03-02 12:50:35 -08:00
Brady
96a8bb90c9 Fix tunnel usage in USAGE.md 2020-03-02 13:41:21 -06:00
Brady
0ca3c496de Fix tunnel command usage 2020-03-02 13:40:43 -06:00
aUniqueUser
0434e1c5d3 Add more entries to MineProcess 2020-02-29 12:24:06 -05:00
aUniqueUser
4c79701d22 Make desktop notifications more useful 2020-02-29 11:28:18 -05:00
Bella
5f49bedc42 Change 1.14 to 1.15 in SETUP.md 2020-02-28 17:26:59 -05:00
Leijurv
d9fc825b0f Merge pull request #1336 from S-B99/patch-1
Update USAGE.md as per #1332
2020-02-27 18:07:16 -08:00
Leijurv
17c691b1cf the whole point is its better to do something nonsensical than to crash, so lets continue in that direction 2020-02-27 18:06:11 -08:00
Leijurv
9fb46946b5 fix sprint while paused bug, fixes #1331 2020-02-27 18:05:48 -08:00
fw4hre0xxq
220fa79057 fix #1339 2020-02-27 17:14:41 -08:00
Bella Who
f1f4adf8a6 Update USAGE.md as per #1332 2020-02-27 17:42:12 -05:00
Leijurv
448dd979a2 Merge pull request #1332 from aUniqueUser/master
#740 (Custom tunneling) Updated for new command system
2020-02-27 14:29:18 -08:00
Leijurv
3386947522 Merge pull request #1020 from Xephorix/patch-1
Update USAGE.md
2020-02-27 09:25:25 -08:00
aUniqueUser
628ec0f2b5 updated longDesc 2020-02-26 13:04:10 -05:00
aUniqueUser
e3b91c884a More logical argument order 2020-02-26 12:30:07 -05:00
aUniqueUser
10bb935a42 Merge pull request #1 from CDAGaming/CDAGaming-patch-1
[Change] Adjustments
2020-02-26 11:14:45 -05:00
CDAGaming
6f136a90a2 [Change] Adjustments 2020-02-26 07:55:21 -06:00
aUniqueUser
acd9bcceeb Codacy 2020-02-25 21:47:35 -05:00
aUniqueUser
3c2838df9e lol 2020-02-25 21:22:35 -05:00
aUniqueUser
4b526f7242 Custom Tunneling 2020-02-25 21:13:20 -05:00
Leijurv
61563c9359 builderprocess should use hypothetical sneaking 2020-02-24 19:27:11 -08:00
Leijurv
e854bf59f8 fix sneaking based issues 2020-02-24 18:31:42 -08:00
Leijurv
393a3a87b6 Update USAGE.md 2020-02-24 12:20:13 -08:00
Brady
888b2723e0 Fix critical prefix tag bug 2020-02-23 21:13:51 -06:00
Leijurv
6ed03d0858 Merge pull request #1328 from babbaj/baritoe
toe
2020-02-23 18:55:22 -08:00
Babbaj
ee33666b38 3 days 2020-02-23 21:54:18 -05:00
Babbaj
07c406aa16 baritoe 2020-02-23 21:48:15 -05:00
Brady
c578d5c1a3 Fix additional TrayIcon creation and support Mac notifs 2020-02-23 12:51:14 -06:00
Leijurv
2ea66ea8fc Merge pull request #1324 from aUniqueUser/master
Desktop Notification System
2020-02-23 10:05:30 -08:00
Leijurv
27440fc147 Update README.md 2020-02-22 22:42:22 -08:00
Leijurv
b1f5429db9 Update README.md 2020-02-22 18:37:29 -08:00
Leijurv
042b1ed6d7 Update README.md 2020-02-22 18:37:10 -08:00
aUniqueUser
a8645afbdb Revert "mfw"
This reverts commit 25b85f17a3.
2020-02-22 21:09:36 -05:00
aUniqueUser
25b85f17a3 mfw 2020-02-22 20:41:06 -05:00
aUniqueUser
cf691118b9 comment fixed 2020-02-22 20:19:25 -05:00
aUniqueUser
0dcb9d4b69 Formatting 2020-02-22 20:12:43 -05:00
aUniqueUser
2d2571cff5 Desktop Notification System 2020-02-22 18:31:41 -05:00
Leijurv
ec8d5c0f4d Merge pull request #1314 from babbaj/proguard-patch
Remove string parsing functions from -assumenosideeffects
2020-02-20 17:35:21 -08:00
Babbaj
85d63c9d7f Exceptions are side effects 2020-02-20 20:29:36 -05:00
Leijurv
19f70f5a79 Merge pull request #1306 from S-B99/patch-1
Make setup instructions more clear
2020-02-17 14:43:05 -08:00
Bella Who
80955cad8b Make setup instructions more clear 2020-02-17 17:42:05 -05:00
Leijurv
01ba712d33 Update README.md 2020-02-14 13:49:53 -08:00
Leijurv
e0985d3b68 Update README.md 2020-02-14 13:49:15 -08:00
Leijurv
7181d2c91a Merge pull request #1287 from S-B99/master
Add Linux support to issue templates
2020-02-09 17:15:52 -08:00
Bella Who
e66d8616ce fixed space 2020-02-09 19:28:19 -05:00
Bella Who
656dd91004 Update bug.md 2020-02-09 19:12:40 -05:00
Leijurv
d88b3a7799 Merge pull request #1286 from S-B99/master
Make how to use checkboxes more clear in issue templates
2020-02-09 14:54:35 -08:00
Bella Who
7cdbc4acca Update suggestion.md 2020-02-09 17:45:28 -05:00
Bella Who
de68e6630e Update question.md 2020-02-09 17:45:09 -05:00
Bella Who
de89da20b2 Update bug.md 2020-02-09 17:44:50 -05:00
Leijurv
17a06621f5 rootnet shill 2020-02-01 16:42:14 -08:00
Leijurv
b3de840e04 no reason for this now that impact is 1.14.4 for all 2020-01-26 12:41:15 -08:00
Leijurv
539b8ef973 fix oversight in coordinate censorship 2020-01-25 22:35:01 -08:00
Brady
710170ef2d Fix RelativeGoalXZ coordinate mix-up
Basically for many months now RelativeGoalXZ produced (~X, ~Y), not (~X, ~Z).
2020-01-10 20:10:16 -06:00
Conner Vercellino
0fba32853b Create .gitmessage 2019-11-20 12:26:37 -08:00
ads123ads
9f5d9bceaa The grammar mistakes were corrected 2019-10-15 15:34:22 +05:30
Xennex
bd345ae041 Update USAGE.md
added a few commands to the list of "fun / interesting / important ones that you might want to look at"
2019-10-07 09:50:10 -06:00
William Jacobs
426838f33e Added optimization_ideas.txt
This adds optimization_ideas.txt, a text file containing my thoughts on how to make ConnGraph faster.
2019-03-23 20:06:47 -04:00
William Jacobs
458cdd3ddd Fixed size calculation in optimizeForestEdges()
This fixes the code in ConnGraph.optimizeForestEdges() that computes the resulting size after combining two Euler tour trees into one. Technically, the old behavior was still correct, but only by accident; this change is still kind of a bug fix.
2019-03-18 13:21:26 -04:00
William Jacobs
05d678a189 Split removeEdge and optimize() into smaller methods
This moves a bit of functionality from ConnGraph.removeEdge and ConnGraph.optimize() into new methods, in order to improve readability.
2019-03-16 14:42:36 -04:00
William Jacobs
454a2b8ae7 Minor readability improvements
This makes various minor improvements to readability and implementation.
2019-03-16 14:17:40 -04:00
William Jacobs
1536209eb3 Optimization: don't push forest edges if there are no non-forest edges
This optimizes the process of searching for a replacement edge to refrain from pushing forest edges down when a tree does not have any same-level non-forest edges. If a tree doesn't have any such edges, then there definitely isn't a replacement edge at that level, so we can avoid doing extra work.

Interestingly, with this optimization, ConnGraph reduces to a single Euler tour forest if the graph is a forest, with addEdge and removeEdge taking O(log N) (non-amortized) time with high probability.
2019-03-06 22:24:50 -05:00
William Jacobs
a60eac5b6c Initial commit
This adds the initial contents of the repository.
2019-03-06 16:46:45 -05:00
btrekkie
7d95d5f991 Initial commit 2019-03-06 16:36:08 -05:00
William Jacobs
8cf1eb9230 Converted to Maven project
This changes RedBlackNode into a Maven project, by adding pom.xml and changing the directory structure. This should make it easier for other projects to include RedBlackNode as a dependency.
2019-03-06 15:20:01 -05:00
William Jacobs
148e9247d3 Clarified main documentation
This changes README.md and the comment for RedBlackNode to more clearly explain what the project is all about. It emphasizes the fact that RedBlackNode provides public access to the tree's structure. It changes the usage example in README.md from a short RedBlackNode subclass highlighting how easy augmentation is to a medium-length pair of tree and node classes that show how to use insertion, removal, and augmentation.

This change also makes minor improvements to comments for RedBlackNode methods.
2019-03-04 17:01:46 -05:00
Bill Jacobs
6d6b968fd6 Simplified if statements
This simplifies this:

if (a) {
    c;
}
if (b) {
    c;
}

to this:

if (a || b) {
    c;
}
2017-05-13 18:19:03 -05:00
Bill Jacobs
3c75a5e39e Moved TreeList.addAll test to TreeListTest.testAddAll
This moves some code that tests TreeList.addAll from TreeListTest.testAdd to TreeListTest.testAddAll
2016-07-22 17:13:19 -07:00
Bill Jacobs
9534c4ae06 Fixed RedBlackNode.concatenate on two one-node trees
This fixes RedBlackNode.concatenate to work on two one-node trees.  The check for determining which tree had the greater red-black height was incorrect in that case.
2016-07-22 17:03:36 -07:00
Bill Jacobs
5e23bd9c81 Changed SubArrayMinTest to use Integer.bitCount
This changes SubArrayMinTest to use the library method Integer.bitCount rather than a hand-rolled bit counting implementation.
2016-06-24 14:46:37 -07:00
Bill Jacobs
91b5ae633a Fixed SubArrayMin to check children
This fixes SubArrayMin to check the appropriate children of the endpoint nodes, in addition to the children of their ancestors.
2016-06-17 21:54:19 -07:00
Bill Jacobs
8c98d5cc42 Changed createTree to set root's parent to null
This changes createTree to set the "parent" field of the root node to null.
2016-06-06 14:55:58 -07:00
Bill Jacobs
cd4424b94a Fixed calls to augment() in fixSiblingDeletion()
This fixes fixSiblingDeletion() to call augment() in certain cases where augment() returns false.
2016-06-02 20:40:35 -07:00
Bill Jacobs
deb397ed1e Changed fixInsertion to always augment parent
This changes fixInsertion to always augment the node's parent, even if the initial call to augment() returns false, assuming "augment" is true.  When we insert a node, we are supposed to ignore its initial state; thus, we ignore the return value of augment().
2016-05-31 23:07:52 -07:00
Bill Jacobs
4e1fe67095 Updated RedBlackNode.jar to clear links after removing node
This updates RedBlackNode.jar to include the changes in dd0fd1959c.
2016-05-28 17:35:32 -07:00
Bill Jacobs
dd0fd1959c Clear links after removing node
This changes the remove methods to set the parent and child links to be null, so that we're more likely to encounter an exception if we attempt to access the node.
2016-05-28 10:56:08 -07:00
Bill Jacobs
a1dba8a58c Added test for "lca"
This adds SubArrayMinTest, which tests RedBlackNode.lca.
2016-05-26 14:47:27 -07:00
Bill Jacobs
f355e1ed2b Added LCA
This adds a RedBlackNode method for computing the lowest common ancestor of two nodes.
2016-05-26 12:22:32 -07:00
Bill Jacobs
82c1fbdc7b Made fixInsertion return the new root
This changes RedBlackNode.fixInsertion to return the root of the resulting tree.
2016-05-26 10:37:25 -07:00
Bill Jacobs
f7f14ff852 Added RedBlackNode.jar
This adds RedBlackNode.jar for using RedBlackNode in binary form.
2016-05-23 14:00:40 -07:00
Bill Jacobs
754e11ade7 Escaped "<" and ">"
This escapes the "<" and ">" characters in README.md.
2016-05-23 13:57:28 -07:00
Bill Jacobs
389f8ea4e2 Initial commit
This adds the initial contents of the repository.
2016-05-23 13:51:21 -07:00
btrekkie
d3e6f9ae02 Initial commit 2016-05-23 13:43:59 -07:00
235 changed files with 17521 additions and 665 deletions

View File

@@ -11,15 +11,25 @@ Operating system:
Java version:
Minecraft version:
Baritone version:
Forge mods (if used):
Other mods (if used):
## Exception, error or logs
You can find your logs in `%appdata%/.minecraft/logs/` (Windows) or `/Library/Application\ Support/minecraft/logs` (Mac).
Please find your `latest.log` or `debug.log` in this folder and attach it to the issue
Linux: `~/.minecraft/logs/`
Windows: `%appdata%/.minecraft/logs/`
Mac: `/Library/Application\ Support/minecraft/logs/`
## How to reproduce
Add your steps to reproduce the issue/bug experienced here.
## Modified settings
To get the modified settings run `#modified` in game
## Final checklist
- [x] I know how to properly use check boxes
- [ ] I have included the version of Minecraft I'm running, baritone's version and forge mods (if used).
- [ ] I have included logs, exceptions and / or steps to reproduce the issue.
- [ ] I have not used any OwO's or UwU's in this issue.
- [ ] I have not used any OwO's or UwU's in this issue.

View File

@@ -10,4 +10,5 @@ assignees: ''
With as much detail as possible, describe your question and what you may need help with.
## Final checklist
- [ ] I have not used any OwO's or UwU's in this issue.
- [x] I know how to properly use check boxes
- [ ] I have not used any OwO's or UwU's in this issue.

View File

@@ -16,4 +16,5 @@ If applicable, what settings/customizability should be offered to tweak the func
Describe how your suggestion would improve Baritone, or the reason behind it being added.
## Final checklist
- [ ] I have not used any OwO's or UwU's in this issue.
- [x] I know how to properly use check boxes
- [ ] I have not used any OwO's or UwU's in this issue.

39
.github/workflows/gradle_build.yml vendored Normal file
View File

@@ -0,0 +1,39 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: Java CI with Gradle
on:
push:
pull_request:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 8
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew build
- name: Archive Artifacts
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: dist/
- name: Archive mapping.txt
uses: actions/upload-artifact@v2
with:
name: Mappings
path: build/tmp/proguard/mapping.txt

26
.github/workflows/run_tests.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: Tests
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up JDK 9
uses: actions/setup-java@v2
with:
java-version: '8'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Executing tests
run: ./gradlew test

6
.gitignore vendored
View File

@@ -18,6 +18,12 @@ classes/
*.iws
/logs/
# Eclipse Files
.classpath
.project
.settings/
baritone_Client.launch
# Copyright Files
!/.idea/copyright/Baritone.xml
!/.idea/copyright/profiles_settings.xml

31
.gitmessage Normal file
View File

@@ -0,0 +1,31 @@
<emoji> <title> (<ticket>)
# 📝 Update README.md (WD-1234)
# ✅ Add unit test for inputs (WD-1234)
# <emoji> can be:
# 🎨 :art: when improving structure of the code
# ⚡️ :zap: when improving performance
# 🔥 :fire: when removing code or files
# ✨ :sparkles: when introducing new features
# 🚧 :construction: when work in progress
# 🔨 :hammer: when refactoring code
# 📝 :memo: when writing docs
# 💄 :lipstick: when updating the UI and style files
# 📈 :chart_with_upwards_trend: when adding analytics or tracking code
# 🌐 :globe_with_meridians: when adding internationalization and localization
# ✏️ :pencil2: when fixing typos
# 🚚 :truck: when moving or renaming files
# ✅ :white_check_mark: when adding tests
# 👌 :ok_hand: when updating code due to code review changes
# 🐛 :bug: when fixing a bug
# 🚑 :ambulance: when doing a critical hotfix
# 🚨 :rotating_light: when removing linter warnings
# 🔀 :twisted_rightwards_arrows: when merging branches
# ⬆️ :arrow_up: when upgrading dependencies
# ⬇️ :arrow_down: when downgrading dependencies
# 🔧 :wrench: when changing configuration files
# 🔖 :bookmark: when releasing / version tagging
# 💚 :green_heart: when fixing the CI build

View File

@@ -1,29 +0,0 @@
language: java
sudo: required
services:
- docker
install:
- travis_retry docker build -t cabaletta/baritone .
script:
- docker run --rm cabaletta/baritone ./gradlew javadoc
- 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
deploy:
provider: releases
api_key:
secure: YOuiXoJNpB4bW89TQoY2IGXg0tqOKls55YMXsSPU6Mx8WzRu8CjjO/A8KA9nGfNrKM+NucjiKr/h53O2Dp2uyy0i0SLvav/G0MaBMeB1NlPRwFopi6tVPNaoZsvr8NW4BIURhspckYLpOTYWnfmOkIv8q7AxrjUZWPKDlq0dte20UxEqUE6msHJ7U9XlKo/4fX40kvWMfwGI2hTyAtL0cRT1QPsd+uW3OQjAPcQj+jKaWld46V8pBK8g9Qde9mo8HC9NBv97zw1bBF1EFkynW569kElHvaS2Opl2QLGaf66guDbpnqDpGHMhQrDdxsZHJ4RksyITn+8A9UArmbkU35BxKqBeQqOWxod2+M0axdLh1pvX43Q1t9n7RiZBf7GvV8vkXL5Sjf8v6Y4LqkJGhvQkTUwpH+0knwrE761DMCtBC34AiWG70D4u7msmhurkflr9kmRHSj/3lyJ1Q2lkt8L+FOAlQBVs64vXTsfgc6Yge7N0O3UD5hCkrDNoz3BzhNBdCkbdxdKCGip71UZgUNkPy9o3ui8jATNj9ypx3+U8ovqP0XWlJqUZmyeXyNGW9NrLeCkRLTlLnZ/dv6OPONa1oAu4TwF1w5A+TGRFZcZjH/PnZKZDQ1OYQOR6drLKRYdr2unvuf5KUKUGqZ7aYtLGhP0rBvGWddRV7DSmX/s=
all_branches: true
file_glob: true
file:
- dist/*
skip_cleanup: true
on:
tags: true
repo: cabaletta/baritone

View File

@@ -1,7 +1,5 @@
FROM debian:stretch
RUN echo 'deb http://deb.debian.org/debian stretch-backports main' > /etc/apt/sources.list.d/stretch-backports.list
ENV DEBIAN_FRONTEND noninteractive
RUN apt update -y
@@ -10,14 +8,8 @@ RUN apt install \
openjdk-8-jdk \
--assume-yes
RUN apt install -qq --assume-yes mesa-utils libgl1-mesa-glx libxcursor1 libxrandr2 libxxf86vm1 x11-xserver-utils xfonts-base xserver-common
COPY . /code
WORKDIR /code
# this .deb is specially patched to support lwjgl
# source: https://github.com/tectonicus/tectonicus/issues/60#issuecomment-154239173
RUN dpkg -i scripts/xvfb_1.16.4-1_amd64.deb
RUN ./gradlew build

107
README.md
View File

@@ -1,44 +1,65 @@
# Baritone
[![Build Status](https://travis-ci.com/cabaletta/baritone.svg?branch=master)](https://travis-ci.com/cabaletta/baritone/)
[![Release](https://img.shields.io/github/release/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/releases/)
[![License](https://img.shields.io/badge/license-LGPL--3.0%20with%20anime%20exception-green.svg)](LICENSE)
[![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)
[![HitCount](http://hits.dwyl.com/cabaletta/baritone.svg)](http://hits.dwyl.com/cabaletta/baritone/)
[![GitHub All Releases](https://img.shields.io/github/downloads/cabaletta/baritone/total.svg)](https://github.com/cabaletta/baritone/releases/)
[![Minecraft](https://img.shields.io/badge/MC-1.12.2-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/master/)
[![Minecraft](https://img.shields.io/badge/MC-1.13.2-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.13.2/)
[![Minecraft](https://img.shields.io/badge/MC-1.14.4-brightgreen.svg)](https://github.com/cabaletta/baritone/tree/1.14.4/)
[![Code of Conduct](https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?style=flat)](https://github.com/cabaletta/baritone/blob/master/CODE_OF_CONDUCT.md)
[![Known Vulnerabilities](https://snyk.io/test/github/cabaletta/baritone/badge.svg?targetFile=build.gradle)](https://snyk.io/test/github/cabaletta/baritone?targetFile=build.gradle)
[![Contributions welcome](https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat)](https://github.com/cabaletta/baritone/issues/)
[![Issues](https://img.shields.io/github/issues/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/issues/)
[![GitHub issues-closed](https://img.shields.io/github/issues-closed/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/issues?q=is%3Aissue+is%3Aclosed)
[![Pull Requests](https://img.shields.io/github/issues-pr/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/pulls/)
![Code size](https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg)
![GitHub repo size](https://img.shields.io/github/repo-size/cabaletta/baritone.svg)
![Lines of Code](https://tokei.rs/b1/github/cabaletta/baritone?category=code)
[![GitHub contributors](https://img.shields.io/github/contributors/cabaletta/baritone.svg)](https://github.com/cabaletta/baritone/graphs/contributors/)
[![GitHub commits](https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg)](https://github.com/cabaletta/baritone/commit/)
[![Impact integration](https://img.shields.io/badge/Impact%20integration-v1.2.10%20/%20v1.3.5%20/%20v1.4.3-brightgreen.svg)](https://impactclient.net/)
[![ForgeHax integration](https://img.shields.io/badge/ForgeHax%20%22integration%22-scuffed-yellow.svg)](https://github.com/fr1kin/ForgeHax/)
[![Aristois add-on integration](https://img.shields.io/badge/Aristois%20add--on%20integration-v1.3.4%20/%20v1.4.1-green.svg)](https://gitlab.com/emc-mods-indrit/baritone_api)
[![WWE integration](https://img.shields.io/badge/WWE%20%22integration%22-master%3F-green.svg)](https://wweclient.com/)
[![Future integration](https://img.shields.io/badge/Future%20integration-Soon™%3F%3F%3F-red.svg)](https://futureclient.net/)
[![forthebadge](https://forthebadge.com/images/badges/built-with-swag.svg)](http://forthebadge.com/)
[![forthebadge](https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg)](http://forthebadge.com/)
<p align="center">
<a href="https://github.com/cabaletta/baritone/releases/"><img src="https://img.shields.io/github/downloads/cabaletta/baritone/total.svg" alt="GitHub All Releases"/></a>
</p>
A Minecraft pathfinder bot.
<p align="center">
<img src="https://img.shields.io/badge/MC-1.12.2-brightgreen.svg" alt="Minecraft"/>
<img src="https://img.shields.io/badge/MC-1.13.2-brightgreen.svg" alt="Minecraft"/>
<img src="https://img.shields.io/badge/MC-1.14.4-brightgreen.svg" alt="Minecraft"/>
<img src="https://img.shields.io/badge/MC-1.15.2-brightgreen.svg" alt="Minecraft"/>
<img src="https://img.shields.io/badge/MC-1.16.5-brightgreen.svg" alt="Minecraft"/>
</p>
Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://www.youtube.com/watch?v=yI8hgW_m6dQ) made by @Adovin#3153 on Baritone's integration into Impact. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a video I made showing off what it can do.
<p align="center">
<a href="https://travis-ci.com/cabaletta/baritone/"><img src="https://travis-ci.com/cabaletta/baritone.svg?branch=master" alt="Build Status"/></a>
<a href="https://github.com/cabaletta/baritone/releases/"><img src="https://img.shields.io/github/release/cabaletta/baritone.svg" alt="Release"/></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/license-LGPL--3.0%20with%20anime%20exception-green.svg" alt="License"/></a>
<a href="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"><img src="https://api.codacy.com/project/badge/Grade/a73d037823b64a5faf597a18d71e3400" alt="Codacy Badge"/></a>
<a href="https://github.com/cabaletta/baritone/blob/master/CODE_OF_CONDUCT.md"><img src="https://img.shields.io/badge/%E2%9D%A4-code%20of%20conduct-blue.svg?style=flat" alt="Code of Conduct"/></a>
<a href="https://snyk.io/test/github/cabaletta/baritone?targetFile=build.gradle"><img src="https://snyk.io/test/github/cabaletta/baritone/badge.svg?targetFile=build.gradle" alt="Known Vulnerabilities"/></a>
<a href="https://github.com/cabaletta/baritone/issues/"><img src="https://img.shields.io/badge/contributions-welcome-brightgreen.svg?style=flat" alt="Contributions welcome"/></a>
<a href="https://github.com/cabaletta/baritone/issues/"><img src="https://img.shields.io/github/issues/cabaletta/baritone.svg" alt="Issues"/></a>
<a href="https://github.com/cabaletta/baritone/issues?q=is%3Aissue+is%3Aclosed"><img src="https://img.shields.io/github/issues-closed/cabaletta/baritone.svg" alt="GitHub issues-closed"/></a>
<a href="https://github.com/cabaletta/baritone/pulls/"><img src="https://img.shields.io/github/issues-pr/cabaletta/baritone.svg" alt="Pull Requests"/></a>
<a href="https://github.com/cabaletta/baritone/graphs/contributors/"><img src="https://img.shields.io/github/contributors/cabaletta/baritone.svg" alt="GitHub contributors"/></a>
<a href="https://github.com/cabaletta/baritone/commit/"><img src="https://img.shields.io/github/commits-since/cabaletta/baritone/v1.0.0.svg" alt="GitHub commits"/></a>
<img src="https://img.shields.io/github/languages/code-size/cabaletta/baritone.svg" alt="Code size"/>
<img src="https://img.shields.io/github/repo-size/cabaletta/baritone.svg" alt="GitHub repo size"/>
<img src="https://tokei.rs/b1/github/cabaletta/baritone?category=code" alt="Lines of Code"/>
</p>
The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to install the v1.2.* forge api jar from [releases](https://github.com/cabaletta/baritone/releases). Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it.
<p align="center">
<a href="https://impactclient.net/"><img src="https://img.shields.io/badge/Impact%20integration-v1.2.14%20/%20v1.3.8%20/%20v1.4.6%20/%20v1.5.3%20/%20v1.6.3-brightgreen.svg" alt="Impact integration"/></a>
<a href="https://github.com/kami-blue/client"><img src="https://img.shields.io/badge/KAMI%20Blue%20integration-v1.2.14--master-green" alt="KAMI Blue integration"/></a>
<a href="https://github.com/fr1kin/ForgeHax/"><img src="https://img.shields.io/badge/ForgeHax%20%22integration%22-scuffed-yellow.svg" alt="ForgeHax integration"/></a>
<a href="https://aristois.net/"><img src="https://img.shields.io/badge/Aristois%20add--on%20integration-v1.6.3-green.svg" alt="Aristois add-on integration"/></a>
<a href="https://rootnet.dev/"><img src="https://img.shields.io/badge/rootNET%20integration-v1.2.14-green.svg" alt="rootNET integration"/></a>
<a href="https://futureclient.net/"><img src="https://img.shields.io/badge/Future%20integration-v1.2.12%20%2F%20v1.3.6%20%2F%20v1.4.4-red" alt="Future integration"/></a>
<a href="https://rusherhack.org/"><img src="https://img.shields.io/badge/RusherHack%20integration-v1.2.14-green" alt="RusherHack integration"/></a>
</p>
For 1.14.4, [click here](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1). Or [with optifine](https://github.com/cabaletta/baritone/issues/797).
<p align="center">
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/built-with-swag.svg" alt="forthebadge"/></a>
<a href="http://forthebadge.com/"><img src="https://forthebadge.com/images/badges/mom-made-pizza-rolls.svg" alt="forthebadge"/></a>
</p>
A Minecraft pathfinder bot.
[**Baritone Discord Server**](http://discord.gg/s6fRBAUpmr)
Baritone is the pathfinding system used in [Impact](https://impactclient.net/) since 4.4. There's a [showcase video](https://youtu.be/CZkLXWo4Fg4) made by @Adovin#0730 on Baritone which I recommend. [Here's](https://www.youtube.com/watch?v=StquF69-_wI) a (very old!) video I made showing off what it can do. [Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa)
The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone. The second easiest way (for 1.12.2 only) is to install the v1.2.* `api-forge` jar from [releases](https://github.com/cabaletta/baritone/releases). **For 1.12.2 Forge, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.2.15/baritone-api-forge-1.2.15.jar)**. Otherwise, see [Installation & setup](SETUP.md). Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it.
For 1.15.2, [click here](https://www.youtube.com/watch?v=j1qKtCZFURM) and see description. If you need Forge 1.15.2, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.5.3), follow the instructions, and get the `api-forge` jar.
For 1.16.5, [click here](https://www.youtube.com/watch?v=_4eVJ9Qz2J8) and see description. If you need Forge or Fabric 1.16.5, look [here](https://github.com/cabaletta/baritone/releases/tag/v1.6.3) and get the `api-forge` or `api-fabric` jar. **For 1.16.5 Fabric, just click [here](https://github.com/cabaletta/baritone/releases/download/v1.6.3/baritone-api-fabric-1.6.3.jar)**.
This project is an updated version of [MineBot](https://github.com/leijurv/MineBot/),
the original version of the bot for Minecraft 1.8.9, rebuilt for 1.12.2 and 1.13.2. Baritone focuses on reliability and particularly performance (it's over [30x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths).
the original version of the bot for Minecraft 1.8.9, rebuilt for 1.12.2 through 1.16.5. Baritone focuses on reliability and particularly performance (it's over [30x faster](https://github.com/cabaletta/baritone/pull/180#issuecomment-423822928) than MineBot at calculating paths).
Have committed at least once a day from Aug 1 2018 to Aug 1 2019.
Have committed at least once a day from Aug 1, 2018, to Aug 1, 2019.
1Leijurv3DWTrGAfmmiTphjhXLvQiHg7K2
@@ -56,13 +77,17 @@ Here are some links to help to get started:
- [Usage (chat control)](USAGE.md)
## Stars over time
[![Stargazers over time](https://starchart.cc/cabaletta/baritone.svg)](https://starchart.cc/cabaletta/baritone)
# API
The API is heavily documented, you can find the Javadocs for the latest release [here](https://baritone.leijurv.com/).
Please note that usage of anything located outside of the ``baritone.api`` package is not supported by the API release
jar.
Below is an example of basic usage for changing some settings, and then pathing to a X/Z goal.
Below is an example of basic usage for changing some settings, and then pathing to an X/Z goal.
```
BaritoneAPI.getSettings().allowSprint.value = true;
@@ -75,12 +100,22 @@ BaritoneAPI.getProvider().getPrimaryBaritone().getCustomGoalProcess().setGoalAnd
## Can I use Baritone as a library in my custom utility client?
That's what it's for, sure! (As long as usage is in compliance with the LGPL 3.0 License)
That's what it's for, sure! (As long as usage complies with the LGPL 3.0 License)
## How is it so fast?
Magic. (Hours of [leijurv](https://github.com/leijurv/) enduring excruciating pain)
### Additional Special Thanks To:
![YourKit-Logo](https://www.yourkit.com/images/yklogo.png)
YourKit supports open source projects with innovative and intelligent tools for monitoring and profiling Java and .NET applications.
YourKit is the creator of the [YourKit Java Profiler](https://www.yourkit.com/java/profiler/), [YourKit .NET Profiler](https://www.yourkit.com/.net/profiler/), and [YourKit YouMonitor](https://www.yourkit.com/youmonitor/).
We thank them for granting Baritone an OSS license so that we can make our software the best it can be.
## 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

@@ -2,7 +2,7 @@
The easiest way to install Baritone is to install [Impact](https://impactclient.net/), which comes with Baritone.
For 1.14.4, [click here](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1).
You can also use a custom version json for Minecraft, with the [1.14.4](https://www.dropbox.com/s/rkml3hjokd3qv0m/1.14.4-Baritone.zip?dl=1) version or the [1.15.2](https://www.dropbox.com/s/8rx6f0kts9hvd4f/1.15.2-Baritone.zip?dl=1) version or the [1.16.5](https://www.dropbox.com/s/i6f292o2i7o9acp/1.16.5-Baritone.zip?dl=1) version.
Once Baritone is installed, look [here](USAGE.md) for instructions on how to use it.
@@ -11,9 +11,9 @@ These releases are not always completely up to date with latest features, and ar
Link to the releases page: [Releases](https://github.com/cabaletta/baritone/releases)
v1.2.* is for 1.12.2, v1.3.* is for 1.13.2
v1.2.* is for 1.12.2, v1.3.* is for 1.13.2, v1.4.* is for 1.14.4, v1.5.* is for 1.15.2, v1.6.* is for 1.16.2 or 1.16.4 or 1.16.5 (LOL)
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`.
Any official release will be GPG signed by leijurv (44A3EA646EADAC6A). Please verify that the hash of the file you download is in `checksums.txt` and that `checksums_signed.asc` is a valid signature by that 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 .` 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).
@@ -32,11 +32,6 @@ If another one of your Forge mods has a Baritone integration, you want `baritone
- **Forge Standalone**: Same as Standalone, but packaged for Forge. This should be used when Baritone is your only Forge mod, or none of your other Forge mods integrate with Baritone.
- **Unoptimized**: Nothing is obfuscated. This shouldn't be used ever in production.
## More Info
To replace out Impact 4.5's Baritone build with a customized one, build Baritone as above then copy & **rename** `dist/baritone-api-$VERSION$.jar` into `minecraft/libraries/cabaletta/baritone-api/1.2/baritone-api-1.2.jar`, replacing the jar that was previously there. You also need to edit `minecraft/versions/1.12.2-Impact_4.5/1.12.2-Impact_4.5.json`, find the line `"name": "cabaletta:baritone-api:1.2"`, remove the comma from the end, and **entirely remove the NEXT line** (starts with `"url"`). **Restart your launcher** then load as normal.
You can verify whether or not it worked by running `.b version` in chat (only valid in Impact). It should print out the version that you downloaded. Note: The version that comes with 4.5 is `v1.2.3`.
## Build it yourself
- Clone or download Baritone
@@ -47,6 +42,29 @@ You can verify whether or not it worked by running `.b version` in chat (only va
## Command Line
On Mac OSX and Linux, use `./gradlew` instead of `gradlew`.
If you have errors with a package missing please make sure you have setup your environment, and are using Oracle JDK 8.
To check which java you are using do
`java -version` in a command prompt or terminal.
If you are using anything above OpenJDK 8, it might not work because the Java distributions above JDK 8 using may not have the needed javax classes.
Open JDK 8 download: https://openjdk.java.net/install/
#### macOS guide
In order to get JDK 8, Try running the following command:
`% /usr/libexec/java_home -V`
If it doesn't work try this guide: https://stackoverflow.com/questions/46513639/how-to-downgrade-java-from-9-to-8-on-a-macos-eclipse-is-not-running-with-java-9
If you see something like
`% 1.8.0_VERSION, x86_64: "Java SE 8" /Library/Java/JavaVirtualMachines/jdk1.8.0_VERSION.jdk/Contents/Home`
in the list then you've got JDK 8 installed.
In order to get JDK 8 running in the **current terminal window** you will have to run this command:
`% export JAVA_HOME=$(/usr/libexec/java_home -v 1.8)`
To add OpenJDK 8 to your PATH add the export line to the end of your `.zshrc / .bashrc` if you want it to apply to each new terminal. If you're using bash change the .bachrc and if you're using zsh change the .zshrc
Setting up the Environment:
```
@@ -54,6 +72,18 @@ $ gradlew setupDecompWorkspace
$ gradlew --refresh-dependencies
```
Building Baritone:
```
$ gradlew build
```
For minecraft 1.15.2+, run the following instead to include the Forge jars:
```
$ gradlew build -Pbaritone.forge_build
```
Running Baritone:
```
@@ -87,16 +117,6 @@ For information on how to build baritone, see [Building Baritone](#building-bari
![Image](https://i.imgur.com/hrLhG9u.png)
# Building
Make sure that you have properly [setup](#setup) the environment before trying to build it.
## Command Line
```
$ gradlew build
```
## IntelliJ
- Navigate to the gradle tasks on the right tab as follows

View File

@@ -16,12 +16,16 @@ Try `#help` I promise it won't just send you back here =)
"wtf where is cleararea" -> look at `#help sel`
"wtf where is goto death, goto waypoint" -> look at `#help wp` (a "tag" is like "home" (created automatically on right clicking a bed) or "death" (created automatically on death) or "user" (has to be created manually)). So you might want `#wp save user coolbiome` then, to set the goal `#wp goal coolbiome` then `#path` to path to it. For death, `#wp goal death` (remember stuff is clickable!).
"wtf where is goto death, goto waypoint" -> look at `#help wp`
just look at `#help` lmao
Watch this [showcase video](https://youtu.be/CZkLXWo4Fg4)!
# Commands
[Tutorial playlist](https://www.youtube.com/playlist?list=PLnwnJ1qsS7CoQl9Si-RTluuzCo_4Oulpa)
**All** of these commands may need a prefix before them, as above ^.
`help`
@@ -36,21 +40,21 @@ Some common examples:
- `goal clear` to clear the goal
- `cancel` or `stop` to stop everything
- `goto portal` or `goto ender_chest` or `goto block_type` to go to a block. (in Impact, `.goto` is an alias for `.b goto` for the most part)
- `mine diamond_ore iron_ore` to mine diamond ore or iron ore (turn on the setting `legitMine` to only mine ores that it can actually see. It will explore randomly around y=11 until it finds them.) An amount of blocks can also be specified, for example, `mine diamond_ore 64`.
- `click` to click your destination on the screen. Right click path to on top of the block, left click to path into it (either at foot level or eye level), and left click and drag to clear all blocks from an area.
- `follow playerName` to follow a player. `followplayers` to follow any players in range (combine with Kill Aura for a fun time). `followentities` to follow any entities. `followentity pig` to follow entities of a specific type.
- `save waypointName` to save a waypoint. `goto waypointName` to go to it.
- `build` to build a schematic. `build blah` will load `schematics/blah.schematic` and build it with the origin being your player feet. `build blah x y z` to set the origin. Any of those can be relative to your player (`~ 69 ~-420` would build at x=player x, y=69, z=player z-420).
- `mine diamond_ore iron_ore` to mine diamond ore or iron ore (turn on the setting `legitMine` to only mine ores that it can actually see. It will explore randomly around y=11 until it finds them.) An amount of blocks can also be specified, for example, `mine 64 diamond_ore`.
- `click` to click your destination on the screen. Right click path to on top of the block, left click to path into it (either at foot level or eye level), and left click and drag to select an area (`#help sel` to see what you can do with that selection).
- `follow player playerName` to follow a player. `follow players` to follow any players in range (combine with Kill Aura for a fun time). `follow entities` to follow any entities. `follow entity pig` to follow entities of a specific type.
- `wp` for waypoints. A "tag" is like "home" (created automatically on right clicking a bed) or "death" (created automatically on death) or "user" (has to be created manually). So you might want `#wp save user coolbiome`, then to set the goal `#wp goal coolbiome` then `#path` to path to it. For death, `#wp goal death` will list waypoints under the "death" tag (remember stuff is clickable!)
- `build` to build a schematic. `build blah.schematic` will load `schematics/blah.schematic` and build it with the origin being your player feet. `build blah.schematic x y z` to set the origin. Any of those can be relative to your player (`~ 69 ~-420` would build at x=player x, y=69, z=player z-420).
- `schematica` to build the schematic that is currently open in schematica
- `tunnel` to dig just straight ahead and make a tunnel
- `farm` to automatically harvest, replant, or bone meal crops
- `tunnel` to dig and make a tunnel, 1x2. It will only deviate from the straight line if necessary such as to avoid lava. For a dumber tunnel that is really just cleararea, you can `tunnel 3 2 100`, to clear an area 3 high, 2 wide, and 100 deep.
- `farm` to automatically harvest, replant, or bone meal crops. Use `farm <range>` or `farm <range> <waypoint>` to limit the max distance from the starting point or a waypoint.
- `axis` to go to an axis or diagonal axis at y=120 (`axisHeight` is a configurable setting, defaults to 120).
- `explore x z` to explore the world from the origin of x,z. Leave out x and z to default to player feet. This will continually path towards the closest chunk to the origin that it's never seen before. `explorefilter filter.json` with optional invert can be used to load in a list of chunks to load.
- `invert` to invert the current goal and path. This gets as far away from it as possible, instead of as close as possible. For example, do `goal` then `invert` to run as far as possible from where you're standing at the start.
- `version` to get the version of Baritone you're running
- `damn` daniel
For the rest of the commands, you can take a look at the code [here](https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/utils/ExampleBaritoneControl.java).
For the rest of the commands, you can take a look at the code [here](https://baritone.leijurv.com/baritone/api/Settings.html).
All the settings and documentation are <a href="https://github.com/cabaletta/baritone/blob/master/src/api/java/baritone/api/Settings.java">here</a>. If you find HTML easier to read than Javadoc, you can look <a href="https://baritone.leijurv.com/baritone/api/Settings.html#field.detail">here</a>.
@@ -71,6 +75,8 @@ There are about a hundred settings, but here are some fun / interesting / import
- `worldExploringChunkOffset`
- `acceptableThrowawayItems`
- `blocksToAvoidBreaking`
- `mineScanDroppedItems`
- `allowDiagonalAscend`
@@ -90,4 +96,4 @@ So you'll need to use the `#` prefix or edit `baritone/settings.txt` in your Min
## Why can I do `.goto x z` in Impact but nowhere else? Why can I do `-path to x z` in KAMI but nowhere else?
These are custom commands that they added; those aren't from Baritone.
The equivalent you're looking for is `goal x z` then `path`.
The equivalent you're looking for is `goto x z`.

View File

@@ -16,7 +16,7 @@
*/
group 'baritone'
version '1.2.11'
version '1.2.15'
buildscript {
repositories {
@@ -26,7 +26,7 @@ buildscript {
}
maven {
name = 'SpongePowered'
url = 'http://repo.spongepowered.org/maven'
url = 'https://repo.spongepowered.org/repository/maven-public/'
}
jcenter()
}
@@ -42,6 +42,7 @@ import baritone.gradle.task.CreateDistTask
import baritone.gradle.task.ProguardTask
apply plugin: 'java'
apply plugin: 'maven'
apply plugin: 'net.minecraftforge.gradle.tweaker-client'
apply plugin: 'org.spongepowered.mixin'
@@ -80,7 +81,7 @@ repositories {
maven {
name = 'spongepowered-repo'
url = 'http://repo.spongepowered.org/maven/'
url = 'https://repo.spongepowered.org/repository/maven-public/'
}
maven {
@@ -117,6 +118,12 @@ javadoc {
jar {
from sourceSets.launch.output, sourceSets.api.output
if (!getProject().hasProperty("baritone.forge_build")) {
exclude "**/BaritoneForgeModXD.class"
exclude "**/mods.toml"
}
preserveFileTimestamps = false
reproducibleFileOrder = true
@@ -138,3 +145,25 @@ task proguard(type: ProguardTask) {
task createDist(type: CreateDistTask, dependsOn: proguard)
build.finalizedBy(createDist)
install {
def jarApiName = String.format("%s-api-%s", rootProject.name, version.toString())
def jarApiForgeName = String.format("%s-api-forge-%s", rootProject.name, version.toString())
def jarSAName = String.format("%s-standalone-%s", rootProject.name, version.toString())
def jarSAForgeName = String.format("%s-standalone-forge-%s", rootProject.name, version.toString())
artifacts {
archives file("$buildDir/libs/"+jarApiName+".jar")
archives file("$buildDir/libs/"+jarApiForgeName+".jar")
archives file("$buildDir/libs/"+jarSAName+".jar")
archives file("$buildDir/libs/"+jarSAForgeName+".jar")
}
repositories.mavenInstaller {
addFilter('api') { artifact, file -> artifact.name == "baritone-api" }
addFilter('api-forge') { artifact, file -> artifact.name == "baritone-api-forge" }
addFilter('standalone') { artifact, file -> artifact.name == "baritone-standalone" }
addFilter('standalone-forge') { artifact, file -> artifact.name == "baritone-standalone-forge" }
}
}
install.dependsOn(build)

View File

@@ -21,13 +21,21 @@ import baritone.gradle.util.Determinizer;
import baritone.gradle.util.MappingType;
import baritone.gradle.util.ReobfWrapper;
import org.apache.commons.io.IOUtils;
import org.gradle.api.JavaVersion;
import org.gradle.api.NamedDomainObjectContainer;
import org.gradle.api.artifacts.Configuration;
import org.gradle.api.artifacts.Dependency;
import org.gradle.api.internal.file.IdentityFileResolver;
import org.gradle.api.internal.plugins.DefaultConvention;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskCollection;
import org.gradle.api.tasks.compile.ForkOptions;
import org.gradle.api.tasks.compile.JavaCompile;
import org.gradle.internal.Pair;
import org.gradle.internal.jvm.Jvm;
import org.gradle.internal.jvm.inspection.DefaultJvmVersionDetector;
import org.gradle.process.internal.DefaultExecActionFactory;
import java.io.*;
import java.lang.reflect.Field;
@@ -101,6 +109,101 @@ public class ProguardTask extends BaritoneGradleTask {
}
}
private String getJavaBinPathForProguard() throws Exception {
String path;
try {
path = findJavaPathByGradleConfig();
if (path != null) return path;
}
catch (Exception ex) {
System.err.println("Unable to find java by javaCompile options");
ex.printStackTrace();
}
try {
path = findJavaByJavaHome();
if (path != null) return path;
}
catch(Exception ex) {
System.err.println("Unable to find java by JAVA_HOME");
ex.printStackTrace();
}
path = findJavaByGradleCurrentRuntime();
if (path != null) return path;
throw new Exception("Unable to find java to determine ProGuard libraryjars. Please specify forkOptions.executable in javaCompile," +
" JAVA_HOME environment variable, or make sure to run Gradle with the correct JDK (a v1.8 only)");
}
private String findJavaByGradleCurrentRuntime() {
String path = Jvm.current().getJavaExecutable().getAbsolutePath();
if (this.validateJavaVersion(path)) {
System.out.println("Using Gradle's runtime Java for ProGuard");
return path;
}
return null;
}
private String findJavaByJavaHome() {
final String javaHomeEnv = System.getenv("JAVA_HOME");
if (javaHomeEnv != null) {
String path = Jvm.forHome(new File(javaHomeEnv)).getJavaExecutable().getAbsolutePath();
if (this.validateJavaVersion(path)) {
System.out.println("Detected Java path by JAVA_HOME");
return path;
}
}
return null;
}
private String findJavaPathByGradleConfig() {
final TaskCollection<JavaCompile> javaCompiles = super.getProject().getTasks().withType(JavaCompile.class);
final JavaCompile compileTask = javaCompiles.iterator().next();
final ForkOptions forkOptions = compileTask.getOptions().getForkOptions();
if (forkOptions != null) {
String javacPath = forkOptions.getExecutable();
if (javacPath != null) {
File javacFile = new File(javacPath);
if (javacFile.exists()) {
File[] maybeJava = javacFile.getParentFile().listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return name.equals("java");
}
});
if (maybeJava != null && maybeJava.length > 0) {
String path = maybeJava[0].getAbsolutePath();
if (this.validateJavaVersion(path)) {
System.out.println("Detected Java path by forkOptions");
return path;
}
}
}
}
}
return null;
}
private boolean validateJavaVersion(String java) {
final JavaVersion javaVersion = new DefaultJvmVersionDetector(new DefaultExecActionFactory(new IdentityFileResolver())).getJavaVersion(java);
if (!javaVersion.getMajorVersion().equals("8")) {
System.out.println("Failed to validate Java version " + javaVersion.toString() + " [" + java + "] for ProGuard libraryjars");
// throw new RuntimeException("Java version incorrect: " + javaVersion.getMajorVersion() + " for " + java);
return false;
}
System.out.println("Validated Java version " + javaVersion.toString() + " [" + java + "] for ProGuard libraryjars");
return true;
}
private void generateConfigs() throws Exception {
Files.copy(getRelativeFile(PROGUARD_CONFIG_TEMPLATE), getTemporaryFile(PROGUARD_CONFIG_DEST), REPLACE_EXISTING);
@@ -110,7 +213,7 @@ public class ProguardTask extends BaritoneGradleTask {
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();
Process p = new ProcessBuilder(this.getJavaBinPathForProguard(), "-verbose").start();
String out = IOUtils.toString(p.getInputStream(), "UTF-8").split("\n")[0].split("Opened ")[1].replace("]", "");
template.add(2, "-libraryjars '" + out + "'");

59
scripts/proguard.pro vendored
View File

@@ -23,6 +23,13 @@
-keep class baritone.api.utils.MyChunkPos { *; } # even in standalone we need to keep this for gson reflect
# Keep any class or member annotated with @KeepName so we dont have to put everything in the script
-keep,allowobfuscation @interface baritone.KeepName
-keep @baritone.KeepName class *
-keepclassmembers class * {
@baritone.KeepName *;
}
# setting names are reflected from field names, so keep field names
-keepclassmembers class baritone.api.Settings {
public <fields>;
@@ -74,7 +81,7 @@
-libraryjars 'tempLibraries/netty-all-4.1.9.Final.jar'
-libraryjars 'tempLibraries/oshi-core-1.1.jar'
-libraryjars 'tempLibraries/patchy-1.1.jar'
-libraryjars 'tempLibraries/patchy-1.2.jar'
-libraryjars 'tempLibraries/platform-3.4.0.jar'
-libraryjars 'tempLibraries/realms-1.10.22.jar'
-libraryjars 'tempLibraries/soundsystem-20120107.jar'
@@ -181,19 +188,19 @@
-assumenosideeffects public class java.lang.* extends java.lang.Number {
public static java.lang.String toString(byte);
public static java.lang.Byte valueOf(byte);
public static byte parseByte(java.lang.String);
public static byte parseByte(java.lang.String,int);
public static java.lang.Byte valueOf(java.lang.String,int);
public static java.lang.Byte valueOf(java.lang.String);
public static java.lang.Byte decode(java.lang.String);
# public static byte parseByte(java.lang.String);
# public static byte parseByte(java.lang.String,int);
# public static java.lang.Byte valueOf(java.lang.String,int);
# public static java.lang.Byte valueOf(java.lang.String);
# public static java.lang.Byte decode(java.lang.String);
public int compareTo(java.lang.Byte);
public static java.lang.String toString(short);
public static short parseShort(java.lang.String);
public static short parseShort(java.lang.String,int);
public static java.lang.Short valueOf(java.lang.String,int);
public static java.lang.Short valueOf(java.lang.String);
# public static short parseShort(java.lang.String);
# public static short parseShort(java.lang.String,int);
# public static java.lang.Short valueOf(java.lang.String,int);
# public static java.lang.Short valueOf(java.lang.String);
public static java.lang.Short valueOf(short);
public static java.lang.Short decode(java.lang.String);
# public static java.lang.Short decode(java.lang.String);
public static short reverseBytes(short);
public int compareTo(java.lang.Short);
public static java.lang.String toString(int,int);
@@ -201,10 +208,10 @@
public static java.lang.String toOctalString(int);
public static java.lang.String toBinaryString(int);
public static java.lang.String toString(int);
public static int parseInt(java.lang.String,int);
public static int parseInt(java.lang.String);
public static java.lang.Integer valueOf(java.lang.String,int);
public static java.lang.Integer valueOf(java.lang.String);
# public static int parseInt(java.lang.String,int);
# public static int parseInt(java.lang.String);
# public static java.lang.Integer valueOf(java.lang.String,int);
# public static java.lang.Integer valueOf(java.lang.String);
public static java.lang.Integer valueOf(int);
public static java.lang.Integer getInteger(java.lang.String);
public static java.lang.Integer getInteger(java.lang.String,int);
@@ -226,12 +233,12 @@
public static java.lang.String toOctalString(long);
public static java.lang.String toBinaryString(long);
public static java.lang.String toString(long);
public static long parseLong(java.lang.String,int);
public static long parseLong(java.lang.String);
public static java.lang.Long valueOf(java.lang.String,int);
public static java.lang.Long valueOf(java.lang.String);
# public static long parseLong(java.lang.String,int);
# public static long parseLong(java.lang.String);
# public static java.lang.Long valueOf(java.lang.String,int);
# public static java.lang.Long valueOf(java.lang.String);
public static java.lang.Long valueOf(long);
public static java.lang.Long decode(java.lang.String);
# public static java.lang.Long decode(java.lang.String);
public static java.lang.Long getLong(java.lang.String);
public static java.lang.Long getLong(java.lang.String,long);
public static java.lang.Long getLong(java.lang.String,java.lang.Long);
@@ -248,9 +255,9 @@
public int compareTo(java.lang.Long);
public static java.lang.String toString(float);
public static java.lang.String toHexString(float);
public static java.lang.Float valueOf(java.lang.String);
# public static java.lang.Float valueOf(java.lang.String);
public static java.lang.Float valueOf(float);
public static float parseFloat(java.lang.String);
# public static float parseFloat(java.lang.String);
public static boolean isNaN(float);
public static boolean isInfinite(float);
public static int floatToIntBits(float);
@@ -262,9 +269,9 @@
public int compareTo(java.lang.Float);
public static java.lang.String toString(double);
public static java.lang.String toHexString(double);
public static java.lang.Double valueOf(java.lang.String);
public static java.lang.Double valueOf(double);
public static double parseDouble(java.lang.String);
# public static java.lang.Double valueOf(java.lang.String);
# public static java.lang.Double valueOf(double);
# public static double parseDouble(java.lang.String);
public static boolean isNaN(double);
public static boolean isInfinite(double);
public static long doubleToLongBits(double);
@@ -374,3 +381,5 @@
public java.lang.String substring(int);
public java.lang.String substring(int,int);
}
-printmapping mapping.txt

Binary file not shown.

View File

@@ -20,13 +20,13 @@ package baritone.api;
import baritone.api.behavior.ILookBehavior;
import baritone.api.behavior.IPathingBehavior;
import baritone.api.cache.IWorldProvider;
import baritone.api.command.manager.ICommandManager;
import baritone.api.event.listener.IEventBus;
import baritone.api.pathing.calc.IPathingControlManager;
import baritone.api.process.*;
import baritone.api.selection.ISelectionManager;
import baritone.api.utils.IInputOverrideHandler;
import baritone.api.utils.IPlayerContext;
import baritone.api.command.manager.ICommandManager;
/**
* @author Brady

View File

@@ -17,8 +17,10 @@
package baritone.api;
import baritone.api.utils.NotificationHelper;
import baritone.api.utils.SettingsUtil;
import baritone.api.utils.TypeUtils;
import baritone.api.utils.gui.BaritoneToast;
import net.minecraft.block.Block;
import net.minecraft.client.Minecraft;
import net.minecraft.init.Blocks;
@@ -30,9 +32,10 @@ import java.awt.*;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
import java.util.List;
import java.util.*;
import java.util.function.Consumer;
import java.util.function.BiConsumer;
/**
* Baritone's settings. Settings apply to all Baritone instances.
@@ -61,6 +64,19 @@ public final class Settings {
*/
public final Setting<Boolean> allowInventory = new Setting<>(false);
/**
* Disable baritone's auto-tool at runtime, but still assume that another mod will provide auto tool functionality
* <p>
* Specifically, path calculation will still assume that an auto tool will run at execution time, even though
* Baritone itself will not do that.
*/
public final Setting<Boolean> assumeExternalAutoTool = new Setting<>(false);
/**
* Automatically select the best available tool
*/
public final Setting<Boolean> autoTool = new Setting<>(true);
/**
* It doesn't actually take twenty ticks to place a block, this cost is so high
* because we want to generally conserve blocks which might be limited.
@@ -193,6 +209,38 @@ public final class Settings {
)));
/**
* A list of blocks to be treated as correct.
* <p>
* If a schematic asks for any block on this list at a certain position, it will be treated as correct, regardless of what it currently is.
*/
public final Setting<List<Block>> buildSkipBlocks = new Setting<>(new ArrayList<>(Arrays.asList(
)));
/**
* A mapping of blocks to blocks treated as correct in their position
* <p>
* If a schematic asks for a block on this mapping, all blocks on the mapped list will be accepted at that location as well
*/
public final Setting<Map<Block, List<Block>>> buildValidSubstitutes = new Setting<>(new HashMap<>());
/**
* A mapping of blocks to blocks to be built instead
* <p>
* If a schematic asks for a block on this mapping, Baritone will place the first placeable block in the mapped list
*/
public final Setting<Map<Block, List<Block>>> buildSubstitutes = new Setting<>(new HashMap<>());
/**
* A list of blocks to become air
* <p>
* If a schematic asks for a block on this list, only air will be accepted at that location (and nothing on buildIgnoreBlocks)
*/
public final Setting<List<Block>> okIfAir = new Setting<>(new ArrayList<>(Arrays.asList(
)));
/**
* If this is true, the builder will treat all non-air blocks as correct. It will only place new blocks.
*/
@@ -430,6 +478,11 @@ public final class Settings {
*/
public final Setting<Boolean> simplifyUnloadedYCoord = new Setting<>(true);
/**
* Whenever a block changes, repack the whole chunk that it's in
*/
public final Setting<Boolean> repackOnAnyBlockChange = new Setting<>(true);
/**
* If a movement takes this many ticks more than its initial cost estimate, cancel it
*/
@@ -502,6 +555,18 @@ public final class Settings {
*/
public final Setting<Boolean> backfill = new Setting<>(false);
/**
* Shows popup message in the upper right corner, similarly to when you make an advancement
*/
public final Setting<Boolean> logAsToast = new Setting<>(false);
/**
* The time of how long the message in the pop-up will display
* <p>
* If below 1000L (1sec), it's better to disable this
*/
public final Setting<Long> toastTimer = new Setting<>(5000L);
/**
* Print all the debug messages to chat
*/
@@ -533,6 +598,12 @@ public final class Settings {
*/
public final Setting<Boolean> renderGoal = new Setting<>(true);
/**
* Render the goal as a sick animated thingy instead of just a box
* (also controls animation of GoalXZ if {@link #renderGoalXZBeacon} is enabled)
*/
public final Setting<Boolean> renderGoalAnimated = new Setting<>(true);
/**
* Render selection boxes
*/
@@ -602,7 +673,7 @@ public final class Settings {
/**
* When GetToBlockProcess or MineProcess fails to calculate a path, instead of just giving up, mark the closest instance
* of that block as "unreachable" and go towards the next closest. GetToBlock expands this seaarch to the whole "vein"; MineProcess does not.
* of that block as "unreachable" and go towards the next closest. GetToBlock expands this search to the whole "vein"; MineProcess does not.
* This is because MineProcess finds individual impossible blocks (like one block in a vein that has gravel on top then lava, so it can't break)
* Whereas GetToBlock should blacklist the whole "vein" if it can't get to any of them.
*/
@@ -657,6 +728,16 @@ public final class Settings {
*/
public final Setting<Boolean> censorRanCommands = new Setting<>(false);
/**
* Stop using tools just before they are going to break.
*/
public final Setting<Boolean> itemSaver = new Setting<>(false);
/**
* Durability to leave on the tool when using itemSaver
*/
public final Setting<Integer> itemSaverThreshold = new Setting<>(10);
/**
* Always prefer silk touch tools over regular tools. This will not sacrifice speed, but it will always prefer silk
* touch tools over other tools of the same speed. This includes always choosing ANY silk touch tool over your hand.
@@ -700,7 +781,24 @@ public final class Settings {
public final Setting<Integer> maxCachedWorldScanCount = new Setting<>(10);
/**
* When GetToBlock doesn't know any locations for the desired block, explore randomly instead of giving up.
* Sets the minimum y level whilst mining - set to 0 to turn off.
*/
public final Setting<Integer> minYLevelWhileMining = new Setting<>(0);
/**
* This will only allow baritone to mine exposed ores, can be used to stop ore obfuscators on servers that use them.
*/
public final Setting<Boolean> allowOnlyExposedOres = new Setting<>(false);
/**
* When allowOnlyExposedOres is enabled this is the distance around to search.
* <p>
* It is recommended to keep this value low, as it dramatically increases calculation times.
*/
public final Setting<Integer> allowOnlyExposedOresDistance = new Setting<>(1);
/**
* When GetToBlock or non-legit Mine doesn't know any locations for the desired block, explore randomly instead of giving up.
*/
public final Setting<Boolean> exploreForBlocks = new Setting<>(true);
@@ -752,6 +850,27 @@ public final class Settings {
*/
public final Setting<Boolean> layerOrder = new Setting<>(false);
/**
* How high should the individual layers be?
*/
public final Setting<Integer> layerHeight = new Setting<>(1);
/**
* Start building the schematic at a specific layer.
* Can help on larger builds when schematic wants to break things its already built
*/
public final Setting<Integer> startAtLayer = new Setting<>(0);
/**
* If a layer is unable to be constructed, just skip it.
*/
public final Setting<Boolean> skipFailedLayers = new Setting<>(false);
/**
* Only build the selected part of schematics
*/
public final Setting<Boolean> buildOnlySelection = new Setting<>(false);
/**
* How far to move before repeating the build. 0 to disable repeating on a certain axis, 0,0,0 to disable entirely
*/
@@ -762,6 +881,13 @@ public final class Settings {
*/
public final Setting<Integer> buildRepeatCount = new Setting<>(-1);
/**
* Don't notify schematics that they are moved.
* e.g. replacing will replace the same spots for every repetition
* Mainly for backward compatibility.
*/
public final Setting<Boolean> buildRepeatSneaky = new Setting<>(true);
/**
* Allow standing above a block while mining it, in BuilderProcess
* <p>
@@ -870,6 +996,7 @@ public final class Settings {
* Disallow MineBehavior from using X-Ray to see where the ores are. Turn this option on to force it to mine "legit"
* where it will only mine an ore once it can actually see it, so it won't do or know anything that a normal player
* couldn't. If you don't want it to look like you're X-Raying, turn this on
* This will always explore, regardless of exploreForBlocks
*/
public final Setting<Boolean> legitMine = new Setting<>(false);
@@ -956,6 +1083,20 @@ public final class Settings {
*/
public final Setting<Consumer<ITextComponent>> logger = new Setting<>(Minecraft.getMinecraft().ingameGUI.getChatGUI()::printChatMessage);
/**
* The function that is called when Baritone will send a desktop notification. This function can be added to
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value};
*/
public final Setting<BiConsumer<String, Boolean>> notifier = new Setting<>(NotificationHelper::notify);
/**
* The function that is called when Baritone will show a toast. This function can be added to
* via {@link Consumer#andThen(Consumer)} or it can completely be overriden via setting
* {@link Setting#value};
*/
public final Setting<BiConsumer<ITextComponent, ITextComponent>> toaster = new Setting<>(BaritoneToast::addOrUpdate);
/**
* The size of the box that is rendered when the current goal is a GoalYLevel
*/
@@ -1046,6 +1187,40 @@ public final class Settings {
*/
public final Setting<Boolean> renderSelectionCorners = new Setting<>(true);
/**
* Use sword to mine.
*/
public final Setting<Boolean> useSwordToMine = new Setting<>(true);
/**
* Desktop notifications
*/
public final Setting<Boolean> desktopNotifications = new Setting<>(false);
/**
* Desktop notification on path complete
*/
public final Setting<Boolean> notificationOnPathComplete = new Setting<>(true);
/**
* Desktop notification on farm fail
*/
public final Setting<Boolean> notificationOnFarmFail = new Setting<>(true);
/**
* Desktop notification on build finished
*/
public final Setting<Boolean> notificationOnBuildFinished = new Setting<>(true);
/**
* Desktop notification on explore finished
*/
public final Setting<Boolean> notificationOnExploreFinished = new Setting<>(true);
/**
* Desktop notification on mine fail
*/
public final Setting<Boolean> notificationOnMineFail = new Setting<>(true);
/**
* A map of lowercase setting field names to their respective setting

View File

@@ -58,6 +58,15 @@ public interface IPathingBehavior extends IBehavior {
return Optional.of(current.getPath().ticksRemainingFrom(start));
}
/**
* Returns the estimated remaining ticks to the current goal.
* Given that the return type is an optional, {@link Optional#empty()}
* will be returned in the case that there is no current goal.
*
* @return The estimated remaining ticks to the current goal.
*/
Optional<Double> estimatedTicksToGoal();
/**
* @return The current pathing goal
*/

View File

@@ -88,7 +88,7 @@ public interface IWorldScanner {
* Queues the chunks in a square formation around the specified player, using the specified
* range, which represents 1/2 the square's dimensions, where the player is in the center.
*
* @param ctx The player, describing the origin
* @param ctx The player, describing the origin
* @param range The range to repack
* @return The amount of chunks successfully queued for repacking
*/

View File

@@ -34,9 +34,8 @@ import java.util.stream.Stream;
* So basically, you should use it because it provides a small amount of boilerplate,
* but you're not forced to use it.
*
* @see ICommand
*
* @author LoganDark
* @see ICommand
*/
public abstract class Command implements ICommand {

View File

@@ -46,8 +46,8 @@ public interface IArgParserManager {
/**
* Attempt to parse the specified argument with a stateless {@link IArgParser} that outputs the specified class.
*
* @param type The type to try and parse the argument into.
* @param arg The argument to parse.
* @param type The type to try and parse the argument into.
* @param arg The argument to parse.
* @return An instance of the specified class.
* @throws CommandInvalidTypeException If the parsing failed
*/

View File

@@ -18,8 +18,6 @@
package baritone.api.command.argument;
import baritone.api.command.ICommand;
import baritone.api.command.exception.CommandTooManyArgumentsException;
import baritone.api.utils.Helper;
import baritone.api.command.argparser.IArgParser;
import baritone.api.command.datatypes.IDatatype;
import baritone.api.command.datatypes.IDatatypeFor;
@@ -27,6 +25,8 @@ import baritone.api.command.datatypes.IDatatypePost;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidTypeException;
import baritone.api.command.exception.CommandNotEnoughArgumentsException;
import baritone.api.command.exception.CommandTooManyArgumentsException;
import baritone.api.utils.Helper;
import net.minecraft.util.EnumFacing;
import java.util.Deque;
@@ -223,7 +223,7 @@ public interface IArgConsumer {
* @param type The type to peek as
* @param index The index to peek
* @return An instance of the specified type
* @throws CommandInvalidTypeException If the parsing failed
* @throws CommandInvalidTypeException If the parsing failed
* @see IArgParser
* @see #peekAs(Class)
* @see #peekAsOrDefault(Class, Object, int)
@@ -240,7 +240,7 @@ public interface IArgConsumer {
*
* @param type The type to peek as
* @return An instance of the specified type
* @throws CommandInvalidTypeException If the parsing failed
* @throws CommandInvalidTypeException If the parsing failed
* @see IArgParser
* @see #peekAs(Class, int)
* @see #peekAsOrDefault(Class, Object)
@@ -458,7 +458,7 @@ public interface IArgConsumer {
*
* @param type The type to peek as
* @return An instance of the specified type
* @throws CommandInvalidTypeException If the parsing failed
* @throws CommandInvalidTypeException If the parsing failed
* @see IArgParser
* @see #get()
* @see #getAsOrDefault(Class, Object)

View File

@@ -87,7 +87,7 @@ public interface ICommandArgument {
*
* @param type The class to parse this argument into
* @return An instance of the specified type
* @throws CommandInvalidTypeException If the parsing failed
* @throws CommandInvalidTypeException If the parsing failed
*/
<T, S> T getAs(Class<T> type, Class<S> stateType, S state) throws CommandInvalidTypeException;

View File

@@ -17,8 +17,8 @@
package baritone.api.command.datatypes;
import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.util.ResourceLocation;

View File

@@ -17,8 +17,8 @@
package baritone.api.command.datatypes;
import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityList;
import net.minecraft.util.ResourceLocation;
@@ -32,7 +32,19 @@ public enum EntityClassById implements IDatatypeFor<Class<? extends Entity>> {
public Class<? extends Entity> get(IDatatypeContext ctx) throws CommandException {
ResourceLocation id = new ResourceLocation(ctx.getConsumer().getString());
Class<? extends Entity> entity;
if ((entity = EntityList.REGISTRY.getObject(id)) == null) {
try {
entity = EntityList.REGISTRY.getObject(id);
} catch (NoSuchFieldError e) {
// Forge removes EntityList.REGISTRY field and provides the getClass method as a replacement
// See https://github.com/MinecraftForge/MinecraftForge/blob/1.12.x/patches/minecraft/net/minecraft/entity/EntityList.java.patch
try {
entity = (Class<? extends Entity>) EntityList.class.getMethod("getClass", ResourceLocation.class).invoke(null, id);
} catch (Exception ex) {
throw new RuntimeException("EntityList.REGISTRY does not exist and failed to call the Forge-replacement method", ex);
}
}
if (entity == null) {
throw new IllegalArgumentException("no entity found by that id");
}
return entity;

View File

@@ -17,8 +17,8 @@
package baritone.api.command.datatypes;
import baritone.api.utils.BlockOptionalMeta;
import baritone.api.command.exception.CommandException;
import baritone.api.utils.BlockOptionalMeta;
import java.util.stream.Stream;

View File

@@ -17,8 +17,8 @@
package baritone.api.command.datatypes;
import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
import net.minecraft.util.EnumFacing;
import java.util.Locale;

View File

@@ -20,8 +20,8 @@ package baritone.api.command.datatypes;
import baritone.api.IBaritone;
import baritone.api.cache.IWaypoint;
import baritone.api.cache.IWaypointCollection;
import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
import java.util.Comparator;
import java.util.stream.Stream;

View File

@@ -24,9 +24,8 @@ import baritone.api.command.argument.IArgConsumer;
* Provides an {@link IDatatype} with contextual information so
* that it can perform the desired operation on the target level.
*
* @see IDatatype
*
* @author Brady
* @see IDatatype
* @since 9/26/2019
*/
public interface IDatatypeContext {

View File

@@ -34,11 +34,10 @@ public interface IDatatypeFor<T> extends IDatatype {
* if the expected input does not conform to a parseable value. As far as a {@link CommandException} being
* thrown is concerned, see the note below for specifics.
*
* @see IDatatypeContext
*
* @param ctx The context
* @return The parsed data-type
* @throws CommandException If there was an issue parsing using another type or arguments could not be polled.
* @see IDatatypeContext
*/
T get(IDatatypeContext ctx) throws CommandException;
}

View File

@@ -18,8 +18,8 @@
package baritone.api.command.datatypes;
import baritone.api.IBaritone;
import baritone.api.command.helpers.TabCompleteHelper;
import baritone.api.command.exception.CommandException;
import baritone.api.command.helpers.TabCompleteHelper;
import net.minecraft.entity.player.EntityPlayer;
import java.util.List;

View File

@@ -18,8 +18,8 @@
package baritone.api.command.datatypes;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.utils.BetterBlockPos;
import baritone.api.command.exception.CommandException;
import baritone.api.utils.BetterBlockPos;
import java.util.stream.Stream;

View File

@@ -18,16 +18,13 @@
package baritone.api.command.datatypes;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.Goal;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.pathing.goals.GoalXZ;
import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.utils.BetterBlockPos;
import baritone.api.command.exception.CommandException;
import net.minecraft.util.math.MathHelper;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Stream;
public enum RelativeGoal implements IDatatypePost<Goal, BetterBlockPos> {

View File

@@ -18,9 +18,9 @@
package baritone.api.command.datatypes;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalBlock;
import baritone.api.utils.BetterBlockPos;
import baritone.api.command.exception.CommandException;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;

View File

@@ -18,9 +18,9 @@
package baritone.api.command.datatypes;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalXZ;
import baritone.api.utils.BetterBlockPos;
import baritone.api.command.exception.CommandException;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;
@@ -37,7 +37,7 @@ public enum RelativeGoalXZ implements IDatatypePost<GoalXZ, BetterBlockPos> {
final IArgConsumer consumer = ctx.getConsumer();
return new GoalXZ(
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.x)),
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.y))
MathHelper.floor(consumer.getDatatypePost(RelativeCoordinate.INSTANCE, (double) origin.z))
);
}

View File

@@ -18,9 +18,9 @@
package baritone.api.command.datatypes;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.pathing.goals.GoalYLevel;
import baritone.api.utils.BetterBlockPos;
import baritone.api.command.exception.CommandException;
import net.minecraft.util.math.MathHelper;
import java.util.stream.Stream;

View File

@@ -38,7 +38,7 @@ public class CommandUnhandledException extends RuntimeException implements IComm
@Override
public void handle(ICommand command, List<ICommandArgument> args) {
HELPER.logDirect("An unhandled exception occurred. " +
"The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
"The error is in your game's log, please report this at https://github.com/cabaletta/baritone/issues",
TextFormatting.RED);
this.printStackTrace();

View File

@@ -38,8 +38,8 @@ import static baritone.api.utils.Helper.HELPER;
public interface ICommandException {
/**
* @see Exception#getMessage()
* @return The exception details
* @see Exception#getMessage()
*/
String getMessage();

View File

@@ -17,10 +17,10 @@
package baritone.api.command.helpers;
import baritone.api.utils.Helper;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.exception.CommandException;
import baritone.api.command.exception.CommandInvalidTypeException;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.utils.Helper;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;

View File

@@ -19,10 +19,10 @@ package baritone.api.command.helpers;
import baritone.api.BaritoneAPI;
import baritone.api.Settings;
import baritone.api.event.events.TabCompleteEvent;
import baritone.api.utils.SettingsUtil;
import baritone.api.command.argument.IArgConsumer;
import baritone.api.command.manager.ICommandManager;
import baritone.api.event.events.TabCompleteEvent;
import baritone.api.utils.SettingsUtil;
import net.minecraft.util.ResourceLocation;
import java.util.Comparator;
@@ -236,7 +236,6 @@ public class TabCompleteHelper {
* Appends every command in the specified {@link ICommandManager} to this {@link TabCompleteHelper}
*
* @param manager A command manager
*
* @return This {@link TabCompleteHelper}
*/
public TabCompleteHelper addCommands(ICommandManager manager) {
@@ -254,8 +253,8 @@ public class TabCompleteHelper {
public TabCompleteHelper addSettings() {
return append(
BaritoneAPI.getSettings().allSettings.stream()
.filter(s -> !SettingsUtil.javaOnlySetting(s))
.map(Settings.Setting::getName)
.filter(s -> !s.equalsIgnoreCase("logger"))
.sorted(String.CASE_INSENSITIVE_ORDER)
);
}

View File

@@ -18,7 +18,6 @@
package baritone.api.event.events;
import baritone.api.event.events.type.Cancellable;
import baritone.api.event.events.type.Overrideable;
/**
* @author LoganDark

View File

@@ -54,4 +54,18 @@ public interface Goal {
default double heuristic(BlockPos pos) {
return heuristic(pos.getX(), pos.getY(), pos.getZ());
}
/**
* Returns the heuristic at the goal.
* i.e. {@code heuristic() == heuristic(x,y,z)}
* when {@code isInGoal(x,y,z) == true}
* This is needed by {@code PathingBehavior#estimatedTicksToGoal} because
* some Goals actually do not have a heuristic of 0 when that condition is met
*
* @return The estimate number of ticks to satisfy the goal when the goal
* is already satisfied
*/
default double heuristic() {
return 0;
}
}

View File

@@ -57,6 +57,16 @@ public class GoalComposite implements Goal {
return min;
}
@Override
public double heuristic() {
double min = Double.MAX_VALUE;
for (Goal g : goals) {
// just take the highest value that is guaranteed to be inside the goal
min = Math.min(min, g.heuristic());
}
return min;
}
@Override
public String toString() {
return "GoalComposite" + Arrays.toString(goals);

View File

@@ -45,6 +45,11 @@ public class GoalInverted implements Goal {
return -origin.heuristic(x, y, z);
}
@Override
public double heuristic() {
return Double.NEGATIVE_INFINITY;
}
@Override
public String toString() {
return String.format("GoalInverted{%s}", origin.toString());

View File

@@ -19,6 +19,8 @@ package baritone.api.pathing.goals;
import baritone.api.utils.SettingsUtil;
import baritone.api.utils.interfaces.IGoalRenderPos;
import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet;
import it.unimi.dsi.fastutil.doubles.DoubleIterator;
import net.minecraft.util.math.BlockPos;
public class GoalNear implements Goal, IGoalRenderPos {
@@ -51,6 +53,34 @@ public class GoalNear implements Goal, IGoalRenderPos {
return GoalBlock.calculate(xDiff, yDiff, zDiff);
}
@Override
public double heuristic() {// TODO less hacky solution
int range = (int) Math.ceil(Math.sqrt(rangeSq));
DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978
double minOutside = Double.POSITIVE_INFINITY;
for (int dx = -range; dx <= range; dx++) {
for (int dy = -range; dy <= range; dy++) {
for (int dz = -range; dz <= range; dz++) {
double h = heuristic(x + dx, y + dy, z + dz);
if (h < minOutside && isInGoal(x + dx, y + dy, z + dz)) {
maybeAlwaysInside.add(h);
} else {
minOutside = Math.min(minOutside, h);
}
}
}
}
double maxInside = Double.NEGATIVE_INFINITY;
DoubleIterator it = maybeAlwaysInside.iterator();
while (it.hasNext()) {
double inside = it.nextDouble();
if (inside < minOutside) {
maxInside = Math.max(maxInside, inside);
}
}
return maxInside;
}
@Override
public BlockPos getGoalPos() {
return new BlockPos(x, y, z);

View File

@@ -18,6 +18,8 @@
package baritone.api.pathing.goals;
import baritone.api.utils.SettingsUtil;
import it.unimi.dsi.fastutil.doubles.DoubleOpenHashSet;
import it.unimi.dsi.fastutil.doubles.DoubleIterator;
import net.minecraft.util.math.BlockPos;
import java.util.Arrays;
@@ -31,7 +33,7 @@ public class GoalRunAway implements Goal {
private final BlockPos[] from;
private final double distanceSq;
private final int distanceSq;
private final Integer maintainY;
@@ -44,7 +46,7 @@ public class GoalRunAway implements Goal {
throw new IllegalArgumentException();
}
this.from = from;
this.distanceSq = distance * distance;
this.distanceSq = (int) (distance * distance);
this.maintainY = maintainY;
}
@@ -56,7 +58,7 @@ public class GoalRunAway implements Goal {
for (BlockPos p : from) {
int diffX = x - p.getX();
int diffZ = z - p.getZ();
double distSq = diffX * diffX + diffZ * diffZ;
int distSq = diffX * diffX + diffZ * diffZ;
if (distSq < distanceSq) {
return false;
}
@@ -65,7 +67,7 @@ public class GoalRunAway implements Goal {
}
@Override
public double heuristic(int x, int y, int z) {//mostly copied from GoalBlock
public double heuristic(int x, int y, int z) {// mostly copied from GoalBlock
double min = Double.MAX_VALUE;
for (BlockPos p : from) {
double h = GoalXZ.calculate(p.getX() - x, p.getZ() - z);
@@ -80,6 +82,48 @@ public class GoalRunAway implements Goal {
return min;
}
@Override
public double heuristic() {// TODO less hacky solution
int distance = (int) Math.ceil(Math.sqrt(distanceSq));
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int minZ = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
int maxZ = Integer.MIN_VALUE;
for (BlockPos p : from) {
minX = Math.min(minX, p.getX() - distance);
minY = Math.min(minY, p.getY() - distance);
minZ = Math.min(minZ, p.getZ() - distance);
maxX = Math.max(minX, p.getX() + distance);
maxY = Math.max(minY, p.getY() + distance);
maxZ = Math.max(minZ, p.getZ() + distance);
}
DoubleOpenHashSet maybeAlwaysInside = new DoubleOpenHashSet(); // see pull request #1978
double minOutside = Double.POSITIVE_INFINITY;
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
double h = heuristic(x, y, z);
if (h < minOutside && isInGoal(x, y, z)) {
maybeAlwaysInside.add(h);
} else {
minOutside = Math.min(minOutside, h);
}
}
}
}
double maxInside = Double.NEGATIVE_INFINITY;
DoubleIterator it = maybeAlwaysInside.iterator();
while (it.hasNext()) {
double inside = it.nextDouble();
if (inside < minOutside) {
maxInside = Math.max(maxInside, inside);
}
}
return maxInside;
}
@Override
public String toString() {
if (maintainY != null) {

View File

@@ -64,6 +64,11 @@ public class GoalStrictDirection implements Goal {
return heuristic;
}
@Override
public double heuristic() {
return Double.NEGATIVE_INFINITY;
}
@Override
public String toString() {
return String.format(

View File

@@ -75,7 +75,7 @@ public interface IBaritoneProcess {
* to start eating this tick. {@code PauseForAutoEatProcess} should only actually right click once onTick is called with
* {@code isSafeToCancel} true though.
*
* @return Whethor or not if this control is temporary
* @return Whether or not if this control is temporary
*/
boolean isTemporary();

View File

@@ -17,7 +17,29 @@
package baritone.api.process;
import net.minecraft.util.math.BlockPos;
public interface IFarmProcess extends IBaritoneProcess {
void farm();
/**
* Begin to search for crops to farm with in specified aria
* from specified location.
*
* @param range The distance from center to farm from
* @param pos The center position to base the range from
*/
void farm(int range, BlockPos pos);
/**
* Begin to search for nearby crops to farm.
*/
default void farm() {farm(0, null);}
/**
* Begin to search for crops to farm with in specified aria
* from the position the command was executed.
*
* @param range The distance to search for crops to farm
*/
default void farm(int range) {farm(range, null);}
}

View File

@@ -71,4 +71,11 @@ public class CompositeSchematic extends AbstractSchematic {
}
return entry.schematic.desiredState(x - entry.x, y - entry.y, z - entry.z, current, approxPlaceable);
}
@Override
public void reset() {
for (CompositeSchematicEntry entry : schematicArr) {
entry.schematic.reset();
}
}
}

View File

@@ -19,7 +19,6 @@ package baritone.api.schematic;
import baritone.api.utils.BlockOptionalMeta;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import java.util.List;
@@ -44,8 +43,6 @@ public class FillSchematic extends AbstractSchematic {
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
if (bom.matches(current)) {
return current;
} else if (current.getBlock() != Blocks.AIR) {
return Blocks.AIR.getDefaultState();
}
for (IBlockState placeable : approxPlaceable) {
if (bom.matches(placeable)) {

View File

@@ -73,6 +73,11 @@ public interface ISchematic {
*/
IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable);
/**
* Resets possible caches to avoid wrong behavior when moving the schematic around
*/
default void reset() {}
/**
* @return The width (X axis length) of this schematic
*/

View File

@@ -22,10 +22,9 @@ import net.minecraft.block.state.IBlockState;
/**
* A static schematic is capable of providing the desired state at a given position without
* additional context. Schematics of this type are expected to have non-varying contents.
*
* @see #getDirect(int, int, int)
*
* @author Brady
* @see #getDirect(int, int, int)
* @since 12/24/2019
*/
public interface IStaticSchematic extends ISchematic {

View File

@@ -31,6 +31,18 @@ public class ReplaceSchematic extends MaskSchematic {
this.cache = new Boolean[widthX()][heightY()][lengthZ()];
}
@Override
public void reset() {
// it's final, can't use this.cache = new Boolean[widthX()][heightY()][lengthZ()]
for (int x = 0; x < cache.length; x++) {
for (int y = 0; y < cache[0].length; y++) {
for (int z = 0; z < cache[0][0].length; z++) {
cache[x][y][z] = null;
}
}
}
}
@Override
protected boolean partOfMask(int x, int y, int z, IBlockState currentState) {
if (cache[x][y][z] == null) {

View File

@@ -0,0 +1,89 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.api.schematic;
import net.minecraft.block.Block;
import net.minecraft.block.BlockAir;
import net.minecraft.block.properties.IProperty;
import net.minecraft.block.state.IBlockState;
import net.minecraft.init.Blocks;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class SubstituteSchematic extends AbstractSchematic {
private final ISchematic schematic;
private final Map<Block, List<Block>> substitutions;
private final Map<IBlockState, Map<Block, IBlockState>> blockStateCache = new HashMap<>();
public SubstituteSchematic(ISchematic schematic, Map<Block,List<Block>> substitutions) {
super(schematic.widthX(), schematic.heightY(), schematic.lengthZ());
this.schematic = schematic;
this.substitutions = substitutions;
}
@Override
public boolean inSchematic(int x, int y, int z, IBlockState currentState) {
return schematic.inSchematic(x, y, z, currentState);
}
@Override
public IBlockState desiredState(int x, int y, int z, IBlockState current, List<IBlockState> approxPlaceable) {
IBlockState desired = schematic.desiredState(x, y, z, current, approxPlaceable);
Block desiredBlock = desired.getBlock();
if (!substitutions.containsKey(desiredBlock)) {
return desired;
}
List<Block> substitutes = substitutions.get(desiredBlock);
if (substitutes.contains(current.getBlock()) && !(current.getBlock() instanceof BlockAir)) {// don't preserve air, it's almost always there and almost never wanted
return withBlock(desired, current.getBlock());
}
for (Block substitute : substitutes) {
if (substitute instanceof BlockAir) {
return current.getBlock() instanceof BlockAir ? current : Blocks.AIR.getDefaultState(); // can always "place" air
}
for (IBlockState placeable : approxPlaceable) {
if (substitute.equals(placeable.getBlock())) {
return withBlock(desired, placeable.getBlock());
}
}
}
return substitutes.get(0).getDefaultState();
}
private IBlockState withBlock(IBlockState state, Block block) {
if (blockStateCache.containsKey(state) && blockStateCache.get(state).containsKey(block)) {
return blockStateCache.get(state).get(block);
}
Collection<IProperty<?>> properties = state.getPropertyKeys();
IBlockState newState = block.getDefaultState();
for (IProperty<?> property : properties) {
try {
newState = copySingleProp(state, newState, property);
} catch (IllegalArgumentException e) { //property does not exist for target block
}
}
blockStateCache.computeIfAbsent(state, s -> new HashMap<Block,IBlockState>()).put(block, newState);
return newState;
}
private <T extends Comparable<T>> IBlockState copySingleProp(IBlockState fromState, IBlockState toState, IProperty<T> prop) {
return toState.withProperty(prop, fromState.getValue(prop));
}
}

View File

@@ -17,6 +17,7 @@
package baritone.api.utils;
import it.unimi.dsi.fastutil.HashCommon;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.MathHelper;
@@ -79,25 +80,98 @@ public final class BetterBlockPos extends BlockPos {
return longHash(pos.x, pos.y, pos.z);
}
public static final int NUM_X_BITS = 26;
public static final int NUM_Z_BITS = NUM_X_BITS;
public static final int NUM_Y_BITS = 9; // note: even though Y goes from 0 to 255, that doesn't mean 8 bits will "just work" because the deserializer assumes signed. i could change it for just Y to assume unsigned and leave X and Z as signed, however, we know that in 1.17 they plan to add negative Y. for that reason, the better approach is to give the extra bits to Y and leave it as signed.
// also, if 1.17 sticks with the current plan which is -64 to +320, we could have 9 bits for Y and a constant offset of -64 to change it to -128 to +256.
// that would result in the packed long representation of any valid coordinate still being a positive integer
// i like that property, so i will keep num_y_bits at 9 and plan for an offset in 1.17
// it also gives 1 bit of wiggle room in case anything else happens in the future, so we are only using 63 out of 64 bits at the moment
public static final int Z_SHIFT = 0;
public static final int Y_SHIFT = Z_SHIFT + NUM_Z_BITS + 1; // 1 padding bit to make twos complement not overflow
public static final int X_SHIFT = Y_SHIFT + NUM_Y_BITS + 1; // and also here too
public static final long X_MASK = (1L << NUM_X_BITS) - 1L; // X doesn't need padding as the overflow carry bit is just discarded, like a normal long (-1) + (1) = 0
public static final long Y_MASK = (1L << NUM_Y_BITS) - 1L;
public static final long Z_MASK = (1L << NUM_Z_BITS) - 1L;
public static final long POST_ADDITION_MASK = X_MASK << X_SHIFT | Y_MASK << Y_SHIFT | Z_MASK << Z_SHIFT; // required to "manually inline" toLong(-1, -1, -1) here so that javac inserts proper ldc2_w instructions at usage points instead of getstatic
// what's this ^ mask for?
// it allows for efficient offsetting and manipulation of a long packed coordinate
// if we had three ints, x y z, it would be easy to do "y += 1" or "x -= 1"
// but how do you do those things if you have a long with x y and z all stuffed into one primitive?
// adding together two long coordinates actually works perfectly if both sides have X, Y, and Z as all positive, no issues at all
// but when Y or Z is negative, we run into an issue. consider 8 bits: negative one is 11111111 and one is 00000001
// adding them together gives 00000000, zero, **but only because there isn't a 9th bit to carry into**
// if we had, instead, 00000000 11111111 + 00000000 00000001 we would rightly get 00000001 00000000 with the 1 being carried into the 9th position there
// this is exactly what happens. "toLong(0, 1, 0) + toLong(0, -1, 0)" ends up equaling toLong(1, 0, 0) while we'd rather it equal toLong(0, 0, 0)
// so, we simply mask out the unwanted result of the carry by inserting 1 bit of padding space (as added above) between each
// it used to be 000XXXXXXXXXXXXXXXXXXXXXXXXXXYYYYYYYYYZZZZZZZZZZZZZZZZZZZZZZZZZZ
// and now it is 0XXXXXXXXXXXXXXXXXXXXXXXXXX0YYYYYYYYY0ZZZZZZZZZZZZZZZZZZZZZZZZZZ
// we simply place the X Y and Z in slightly different sections of the long, putting a bit of space between each
// the mask ^ is 0111111111111111111111111110111111111011111111111111111111111111
// using that example of (0,1,0) + (0,-1,0), here's what happens
// 0000000000000000000000000000000000001000000000000000000000000000 (this is X=0 Y=1 Z=0)
// + 0000000000000000000000000000111111111000000000000000000000000000 (this is X=0 Y=-1 Z=0)
// = 0000000000000000000000000001000000000000000000000000000000000000
// the unwanted carry bit here ^ is no longer corrupting the least significant bit of X and making it 1!
// now it's just turning on the unused padding bit that we don't care about
// using the mask and bitwise and, we can easily and branchlessly turn off the padding bits just in case something overflow carried into them!
// 0000000000000000000000000001000000000000000000000000000000000000 (the result of the addition from earlier)
// & 0111111111111111111111111110111111111011111111111111111111111111 (this is POST_ADDITION_MASK)
// = 0000000000000000000000000000000000000000000000000000000000000000
// POST_ADDITION_MASK retains the bits that actually form X, Y, and Z, but intentionally turns off the padding bits
// so, we can simply do "(toLong(0, 1, 0) + toLong(0, -1, 0)) & POST_ADDITION_MASK" and correctly get toLong(0, 0, 0)
// which is incredibly fast and efficient, an add then a bitwise AND against a constant
// and it doesn't require us to pull out X, Y, and Z, modify one of them, and put them all back into the long
// that's what the point of the mask is
static {
if (POST_ADDITION_MASK != toLong(-1, -1, -1)) {
throw new IllegalStateException(POST_ADDITION_MASK + " " + toLong(-1, -1, -1)); // sanity check
}
}
public long toLong() {
return toLong(this.x, this.y, this.z);
}
public static BetterBlockPos fromLong(long serialized) {
return new BetterBlockPos(XfromLong(serialized), YfromLong(serialized), ZfromLong(serialized));
}
public static int XfromLong(long serialized) {
return (int) (serialized << (64 - X_SHIFT - NUM_X_BITS) >> (64 - NUM_X_BITS));
}
public static int YfromLong(long serialized) {
return (int) (serialized << (64 - Y_SHIFT - NUM_Y_BITS) >> (64 - NUM_Y_BITS));
}
public static int ZfromLong(long serialized) {
return (int) (serialized << (64 - Z_SHIFT - NUM_Z_BITS) >> (64 - NUM_Z_BITS));
}
public static long toLong(final int x, final int y, final int z) {
return ((long) x & X_MASK) << X_SHIFT | ((long) y & Y_MASK) << Y_SHIFT | ((long) z & Z_MASK) << Z_SHIFT;
}
public static long offsetBy(long pos, int x, int y, int z) {
return (pos + toLong(x, y, z)) & BetterBlockPos.POST_ADDITION_MASK;
}
public static final long HASHCODE_MURMUR_MASK = murmur64(-1);
public static final long ZOBRIST_MURMUR_MASK = murmur64(-2);
public static long longHash(int x, int y, int z) {
// TODO use the same thing as BlockPos.fromLong();
// invertibility would be incredibly useful
/*
* 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;
return longHash(toLong(x, y, z));
}
public static long longHash(long packed) {
return murmur64(HASHCODE_MURMUR_MASK ^ packed);
}
public static long murmur64(long h) {
return HashCommon.murmurHash3(h);
}
@Override
@@ -206,10 +280,10 @@ public final class BetterBlockPos extends BlockPos {
@Nonnull
public String toString() {
return String.format(
"BetterBlockPos{x=%s,y=%s,z=%s}",
SettingsUtil.maybeCensor(x),
SettingsUtil.maybeCensor(y),
SettingsUtil.maybeCensor(z)
"BetterBlockPos{x=%d,y=%d,z=%d}",
x,
y,
z
);
}
}

View File

@@ -234,11 +234,10 @@ public final class BlockOptionalMeta {
/**
* Evaluate the target meta value for the specified state. The target meta value is
* most often that which is influenced by the variant/color property of the block state.
*
* @see #normalize(IBlockState)
*
*
* @param state The state to check
* @return The target meta of the state
* @see #normalize(IBlockState)
*/
public static int stateMeta(IBlockState state) {
return state.getBlock().getMetaFromState(normalize(state));

View File

@@ -24,6 +24,7 @@ import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextFormatting;
import java.util.Arrays;
import java.util.Calendar;
import java.util.stream.Stream;
/**
@@ -47,7 +48,9 @@ public interface Helper {
static ITextComponent getPrefix() {
// Inner text component
ITextComponent baritone = new TextComponentString(BaritoneAPI.getSettings().shortBaritonePrefix.value ? "B" : "Baritone");
final Calendar now = Calendar.getInstance();
final boolean xd = now.get(Calendar.MONTH) == Calendar.APRIL && now.get(Calendar.DAY_OF_MONTH) <= 3;
ITextComponent baritone = new TextComponentString(xd ? "Baritoe" : BaritoneAPI.getSettings().shortBaritonePrefix.value ? "B" : "Baritone");
baritone.getStyle().setColor(TextFormatting.LIGHT_PURPLE);
// Outer brackets
@@ -60,6 +63,77 @@ public interface Helper {
return prefix;
}
/**
* Send a message to display as a toast popup
*
* @param title The title to display in the popup
* @param message The message to display in the popup
*/
default void logToast(ITextComponent title, ITextComponent message) {
mc.addScheduledTask(() -> BaritoneAPI.getSettings().toaster.value.accept(title, message));
}
/**
* Send a message to display as a toast popup
*
* @param title The title to display in the popup
* @param message The message to display in the popup
*/
default void logToast(String title, String message) {
logToast(new TextComponentString(title), new TextComponentString(message));
}
/**
* Send a message to display as a toast popup
*
* @param message The message to display in the popup
*/
default void logToast(String message) {
logToast(Helper.getPrefix(), new TextComponentString(message));
}
/**
* Send a message as a desktop notification
*
* @param message The message to display in the notification
*/
default void logNotification(String message) {
logNotification(message, false);
}
/**
* Send a message as a desktop notification
*
* @param message The message to display in the notification
* @param error Whether to log as an error
*/
default void logNotification(String message, boolean error) {
if (BaritoneAPI.getSettings().desktopNotifications.value) {
logNotificationDirect(message, error);
}
}
/**
* Send a message as a desktop notification regardless of desktopNotifications
* (should only be used for critically important messages)
*
* @param message The message to display in the notification
*/
default void logNotificationDirect(String message) {
logNotificationDirect(message, false);
}
/**
* Send a message as a desktop notification regardless of desktopNotifications
* (should only be used for critically important messages)
*
* @param message The message to display in the notification
* @param error Whether to log as an error
*/
default void logNotificationDirect(String message, boolean error) {
mc.addScheduledTask(() -> BaritoneAPI.getSettings().notifier.value.accept(message, error));
}
/**
* Send a message to chat only if chatDebug is on
*
@@ -71,7 +145,31 @@ public interface Helper {
//System.out.println(message);
return;
}
logDirect(message);
// We won't log debug chat into toasts
// Because only a madman would want that extreme spam -_-
logDirect(message, false);
}
/**
* Send components to chat with the [Baritone] prefix
*
* @param logAsToast Whether to log as a toast notification
* @param components The components to send
*/
default void logDirect(boolean logAsToast, ITextComponent... components) {
ITextComponent component = new TextComponentString("");
if (!logAsToast) {
// If we are not logging as a Toast
// Append the prefix to the base component line
component.appendSibling(getPrefix());
component.appendSibling(new TextComponentString(" "));
}
Arrays.asList(components).forEach(component::appendSibling);
if (logAsToast) {
logToast(getPrefix(), component);
} else {
mc.addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component));
}
}
/**
@@ -80,11 +178,23 @@ public interface Helper {
* @param components The components to send
*/
default void logDirect(ITextComponent... components) {
ITextComponent component = new TextComponentString("");
component.appendSibling(getPrefix());
component.appendSibling(new TextComponentString(" "));
Arrays.asList(components).forEach(component::appendSibling);
Minecraft.getMinecraft().addScheduledTask(() -> BaritoneAPI.getSettings().logger.value.accept(component));
logDirect(BaritoneAPI.getSettings().logAsToast.value, components);
}
/**
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a
* direct response to a chat command)
*
* @param message The message to display in chat
* @param color The color to print that message in
* @param logAsToast Whether to log as a toast notification
*/
default void logDirect(String message, TextFormatting color, boolean logAsToast) {
Stream.of(message.split("\n")).forEach(line -> {
ITextComponent component = new TextComponentString(line.replace("\t", " "));
component.getStyle().setColor(color);
logDirect(logAsToast, component);
});
}
/**
@@ -95,11 +205,18 @@ public interface Helper {
* @param color The color to print that message in
*/
default void logDirect(String message, TextFormatting color) {
Stream.of(message.split("\n")).forEach(line -> {
ITextComponent component = new TextComponentString(line.replace("\t", " "));
component.getStyle().setColor(color);
logDirect(component);
});
logDirect(message, color, BaritoneAPI.getSettings().logAsToast.value);
}
/**
* Send a message to chat regardless of chatDebug (should only be used for critically important messages, or as a
* direct response to a chat command)
*
* @param message The message to display in chat
* @param logAsToast Whether to log as a toast notification
*/
default void logDirect(String message, boolean logAsToast) {
logDirect(message, TextFormatting.GRAY, logAsToast);
}
/**
@@ -109,6 +226,6 @@ public interface Helper {
* @param message The message to display in chat
*/
default void logDirect(String message) {
logDirect(message, TextFormatting.GRAY);
logDirect(message, BaritoneAPI.getSettings().logAsToast.value);
}
}

View File

@@ -20,7 +20,6 @@ package baritone.api.utils;
import baritone.api.cache.IWorldData;
import net.minecraft.block.BlockSlab;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.entity.Entity;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.RayTraceResult;
import net.minecraft.util.math.Vec3d;
@@ -77,6 +76,10 @@ public interface IPlayerContext {
return new Rotation(player().rotationYaw, player().rotationPitch);
}
static double eyeHeight(boolean ifSneaking) {
return ifSneaking ? 1.54 : 1.62;
}
/**
* Returns the block that the crosshair is currently placed over. Updated once per tick.
*
@@ -93,17 +96,4 @@ public interface IPlayerContext {
default boolean isLookingAt(BlockPos pos) {
return getSelectedBlock().equals(Optional.of(pos));
}
/**
* Returns the entity that the crosshair is currently placed over. Updated once per tick.
*
* @return The entity
*/
default Optional<Entity> getSelectedEntity() {
RayTraceResult result = objectMouseOver();
if (result != null && result.typeOfHit == RayTraceResult.Type.ENTITY) {
return Optional.of(result.entityHit);
}
return Optional.empty();
}
}

View File

@@ -0,0 +1,89 @@
/*
* 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 org.apache.commons.lang3.SystemUtils;
import java.awt.*;
import java.io.IOException;
/**
* This class is not called from the main game thread.
* Do not refer to any Minecraft classes, it wouldn't be thread safe.
*
* @author aUniqueUser
*/
public class NotificationHelper {
private static TrayIcon trayIcon;
public static void notify(String text, boolean error) {
if (SystemUtils.IS_OS_WINDOWS) {
windows(text, error);
} else if (SystemUtils.IS_OS_MAC_OSX) {
mac(text);
} else if (SystemUtils.IS_OS_LINUX) {
linux(text);
}
}
private static void windows(String text, boolean error) {
if (SystemTray.isSupported()) {
try {
if (trayIcon == null) {
SystemTray tray = SystemTray.getSystemTray();
Image image = Toolkit.getDefaultToolkit().createImage("");
trayIcon = new TrayIcon(image, "Baritone");
trayIcon.setImageAutoSize(true);
trayIcon.setToolTip("Baritone");
tray.add(trayIcon);
}
trayIcon.displayMessage("Baritone", text, error ? TrayIcon.MessageType.ERROR : TrayIcon.MessageType.INFO);
} catch (Exception e) {
e.printStackTrace();
}
} else {
System.out.println("SystemTray is not supported");
}
}
private static void mac(String text) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("osascript", "-e", "display notification \"" + text + "\" with title \"Baritone\"");
try {
processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
// The only way to display notifications on linux is to use the java-gnome library,
// or send notify-send to shell with a ProcessBuilder. Unfortunately the java-gnome
// library is licenced under the GPL, see (https://en.wikipedia.org/wiki/Java-gnome)
private static void linux(String text) {
ProcessBuilder processBuilder = new ProcessBuilder();
processBuilder.command("notify-send", "-a", "Baritone", text);
try {
processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
}
}

View File

@@ -40,7 +40,16 @@ public final class RayTraceUtils {
* @return The calculated raytrace result
*/
public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance) {
Vec3d start = entity.getPositionEyes(1.0F);
return rayTraceTowards(entity, rotation, blockReachDistance, false);
}
public static RayTraceResult rayTraceTowards(Entity entity, Rotation rotation, double blockReachDistance, boolean wouldSneak) {
Vec3d start;
if (wouldSneak) {
start = inferSneakingEyePosition(entity);
} else {
start = entity.getPositionEyes(1.0F); // do whatever is correct
}
Vec3d direction = RotationUtils.calcVec3dFromRotation(rotation);
Vec3d end = start.add(
direction.x * blockReachDistance,
@@ -49,4 +58,8 @@ public final class RayTraceUtils {
);
return entity.world.rayTraceBlocks(start, end, false, false, true);
}
public static Vec3d inferSneakingEyePosition(Entity entity) {
return new Vec3d(entity.posX, entity.posY + IPlayerContext.eyeHeight(true), entity.posZ);
}
}

View File

@@ -140,6 +140,10 @@ public final class RotationUtils {
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance());
}
public static Optional<Rotation> reachable(IPlayerContext ctx, BlockPos pos, boolean wouldSneak) {
return reachable(ctx.player(), pos, ctx.playerController().getBlockReachDistance(), wouldSneak);
}
/**
* 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,
@@ -153,6 +157,10 @@ public final class RotationUtils {
* @return The optional rotation
*/
public static Optional<Rotation> reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance) {
return reachable(entity, pos, blockReachDistance, false);
}
public static Optional<Rotation> reachable(EntityPlayerSP entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
IBaritone baritone = BaritoneAPI.getProvider().getBaritoneForPlayer(entity);
if (baritone.getPlayerContext().isLookingAt(pos)) {
/*
@@ -165,9 +173,18 @@ public final class RotationUtils {
*
* or if you're a normal person literally all this does it ensure that we don't nudge the pitch to a normal level
*/
return Optional.of(new Rotation(entity.rotationYaw, entity.rotationPitch + 0.0001F));
Rotation hypothetical = new Rotation(entity.rotationYaw, entity.rotationPitch + 0.0001F);
if (wouldSneak) {
// the concern here is: what if we're looking at it now, but as soon as we start sneaking we no longer are
RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, hypothetical, blockReachDistance, true);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK && result.getBlockPos().equals(pos)) {
return Optional.of(hypothetical); // yes, if we sneaked we would still be looking at the block
}
} else {
return Optional.of(hypothetical);
}
}
Optional<Rotation> possibleRotation = reachableCenter(entity, pos, blockReachDistance);
Optional<Rotation> possibleRotation = reachableCenter(entity, pos, blockReachDistance, wouldSneak);
//System.out.println("center: " + possibleRotation);
if (possibleRotation.isPresent()) {
return possibleRotation;
@@ -179,7 +196,7 @@ public final class RotationUtils {
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), blockReachDistance);
possibleRotation = reachableOffset(entity, pos, new Vec3d(pos).add(xDiff, yDiff, zDiff), blockReachDistance, wouldSneak);
if (possibleRotation.isPresent()) {
return possibleRotation;
}
@@ -198,9 +215,10 @@ public final class RotationUtils {
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation
*/
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance) {
Rotation rotation = calcRotationFromVec3d(entity.getPositionEyes(1.0F), offsetPos, new Rotation(entity.rotationYaw, entity.rotationPitch));
RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance);
public static Optional<Rotation> reachableOffset(Entity entity, BlockPos pos, Vec3d offsetPos, double blockReachDistance, boolean wouldSneak) {
Vec3d eyes = wouldSneak ? RayTraceUtils.inferSneakingEyePosition(entity) : entity.getPositionEyes(1.0F);
Rotation rotation = calcRotationFromVec3d(eyes, offsetPos, new Rotation(entity.rotationYaw, entity.rotationPitch));
RayTraceResult result = RayTraceUtils.rayTraceTowards(entity, rotation, blockReachDistance, wouldSneak);
//System.out.println(result);
if (result != null && result.typeOfHit == RayTraceResult.Type.BLOCK) {
if (result.getBlockPos().equals(pos)) {
@@ -222,7 +240,7 @@ public final class RotationUtils {
* @param blockReachDistance The block reach distance of the entity
* @return The optional rotation
*/
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance) {
return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.world, pos), blockReachDistance);
public static Optional<Rotation> reachableCenter(Entity entity, BlockPos pos, double blockReachDistance, boolean wouldSneak) {
return reachableOffset(entity, pos, VecUtils.calculateBlockCenter(entity.world, pos), blockReachDistance, wouldSneak);
}
}

View File

@@ -35,6 +35,7 @@ import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -49,6 +50,7 @@ public class SettingsUtil {
private static final Path SETTINGS_PATH = getMinecraft().gameDir.toPath().resolve("baritone").resolve("settings.txt");
private static final Pattern SETTING_PATTERN = Pattern.compile("^(?<setting>[^ ]+) +(?<value>.+)"); // key and value split by the first space
private static final String[] JAVA_ONLY_SETTINGS = {"logger", "notifier", "toaster"};
private static boolean isComment(String line) {
return line.startsWith("#") || line.startsWith("//");
@@ -110,7 +112,7 @@ public class SettingsUtil {
System.out.println("NULL SETTING?" + setting.getName());
continue;
}
if (setting.getName().equals("logger")) {
if (javaOnlySetting(setting)) {
continue; // NO
}
if (setting.value == setting.defaultValue) {
@@ -164,13 +166,28 @@ public class SettingsUtil {
}
public static String settingToString(Settings.Setting setting) throws IllegalStateException {
if (setting.getName().equals("logger")) {
return "logger";
if (javaOnlySetting(setting)) {
return setting.getName();
}
return setting.getName() + " " + settingValueToString(setting);
}
/**
* This should always be the same as whether the setting can be parsed from or serialized to a string
*
* @param the setting
* @return true if the setting can not be set or read by the user
*/
public static boolean javaOnlySetting(Settings.Setting setting) {
for (String name : JAVA_ONLY_SETTINGS) { // no JAVA_ONLY_SETTINGS.contains(...) because that would be case sensitive
if (setting.getName().equalsIgnoreCase(name)) {
return true;
}
}
return false;
}
public static void parseAndApply(Settings settings, String settingName, String settingValue) throws IllegalStateException, NumberFormatException {
Settings.Setting setting = settings.byLowerName.get(settingName);
if (setting == null) {
@@ -261,6 +278,36 @@ public class SettingsUtil {
public boolean accepts(Type type) {
return List.class.isAssignableFrom(TypeUtils.resolveBaseClass(type));
}
},
MAPPING() {
@Override
public Object parse(ParserContext context, String raw) {
Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
Parser keyParser = Parser.getParser(keyType);
Parser valueParser = Parser.getParser(valueType);
return Stream.of(raw.split(",(?=[^,]*->)"))
.map(s -> s.split("->"))
.collect(Collectors.toMap(s -> keyParser.parse(context, s[0]), s -> valueParser.parse(context, s[1])));
}
@Override
public String toString(ParserContext context, Object value) {
Type keyType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[0];
Type valueType = ((ParameterizedType) context.getSetting().getType()).getActualTypeArguments()[1];
Parser keyParser = Parser.getParser(keyType);
Parser valueParser = Parser.getParser(valueType);
return ((Map<?,?>) value).entrySet().stream()
.map(o -> keyParser.toString(context, o.getKey()) + "->" + valueParser.toString(context, o.getValue()))
.collect(Collectors.joining(","));
}
@Override
public boolean accepts(Type type) {
return Map.class.isAssignableFrom(TypeUtils.resolveBaseClass(type));
}
};
private final Class<?> cla$$;

View File

@@ -0,0 +1,78 @@
/*
* 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.gui;
import net.minecraft.client.gui.toasts.GuiToast;
import net.minecraft.client.gui.toasts.IToast;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
public class BaritoneToast implements IToast {
private String title;
private String subtitle;
private long firstDrawTime;
private boolean newDisplay;
private long totalShowTime;
public BaritoneToast(ITextComponent titleComponent, ITextComponent subtitleComponent, long totalShowTime) {
this.title = titleComponent.getFormattedText();
this.subtitle = subtitleComponent == null ? null : subtitleComponent.getFormattedText();
this.totalShowTime = totalShowTime;
}
public Visibility draw(GuiToast toastGui, long delta) {
if (this.newDisplay) {
this.firstDrawTime = delta;
this.newDisplay = false;
}
toastGui.getMinecraft().getTextureManager().bindTexture(new ResourceLocation("textures/gui/toasts.png"));
GlStateManager.color(1.0F, 1.0F, 1.0F, 255.0f);
toastGui.drawTexturedModalRect(0, 0, 0, 32, 160, 32);
if (this.subtitle == null) {
toastGui.getMinecraft().fontRenderer.drawString(this.title, 18, 12, -11534256);
} else {
toastGui.getMinecraft().fontRenderer.drawString(this.title, 18, 7, -11534256);
toastGui.getMinecraft().fontRenderer.drawString(this.subtitle, 18, 18, -16777216);
}
return delta - this.firstDrawTime < totalShowTime ? Visibility.SHOW : Visibility.HIDE;
}
public void setDisplayedText(ITextComponent titleComponent, ITextComponent subtitleComponent) {
this.title = titleComponent.getFormattedText();
this.subtitle = subtitleComponent == null ? null : subtitleComponent.getFormattedText();
this.newDisplay = true;
}
public static void addOrUpdate(GuiToast toast, ITextComponent title, ITextComponent subtitle, long totalShowTime) {
BaritoneToast baritonetoast = toast.getToast(BaritoneToast.class, new Object());
if (baritonetoast == null) {
toast.add(new BaritoneToast(title, subtitle, totalShowTime));
} else {
baritonetoast.setDisplayedText(title, subtitle);
}
}
public static void addOrUpdate(ITextComponent title, ITextComponent subtitle) {
addOrUpdate(net.minecraft.client.Minecraft.getMinecraft().getToastGui(), title, subtitle, baritone.api.BaritoneAPI.getSettings().toastTimer.value);
}
}

View File

@@ -23,7 +23,6 @@ import baritone.api.event.events.BlockInteractEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.WorldEvent;
import baritone.api.event.events.type.EventState;
import baritone.utils.BaritoneAutoTest;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.gui.GuiScreen;
@@ -63,17 +62,6 @@ public class MixinMinecraft {
BaritoneAPI.getProvider().getPrimaryBaritone();
}
@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(
@@ -145,7 +133,7 @@ public class MixinMinecraft {
)
private boolean isAllowUserInput(GuiScreen screen) {
// allow user input is only the primary baritone
return (BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().getCurrent() != null && player != null) || screen.allowUserInput;
return (BaritoneAPI.getProvider().getPrimaryBaritone().getPathingBehavior().isPathing() && player != null) || screen.allowUserInput;
}
@Inject(

View File

@@ -17,13 +17,19 @@
package baritone.launch.mixins;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.IBaritone;
import baritone.api.event.events.ChunkEvent;
import baritone.api.event.events.type.EventState;
import baritone.cache.CachedChunk;
import net.minecraft.client.entity.EntityPlayerSP;
import net.minecraft.client.network.NetHandlerPlayClient;
import net.minecraft.network.play.server.SPacketBlockChange;
import net.minecraft.network.play.server.SPacketChunkData;
import net.minecraft.network.play.server.SPacketCombatEvent;
import net.minecraft.network.play.server.SPacketMultiBlockChange;
import net.minecraft.util.math.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -45,7 +51,8 @@ public class MixinNetHandlerPlayClient {
)
private void preRead(SPacketChunkData packetIn, CallbackInfo ci) {
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
if (ibaritone.getPlayerContext().player().connection == (NetHandlerPlayClient) (Object) this) {
EntityPlayerSP player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
new ChunkEvent(
EventState.PRE,
@@ -64,7 +71,8 @@ public class MixinNetHandlerPlayClient {
)
private void postHandleChunkData(SPacketChunkData packetIn, CallbackInfo ci) {
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
if (ibaritone.getPlayerContext().player().connection == (NetHandlerPlayClient) (Object) this) {
EntityPlayerSP player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
new ChunkEvent(
EventState.POST,
@@ -77,6 +85,68 @@ public class MixinNetHandlerPlayClient {
}
}
@Inject(
method = "handleBlockChange",
at = @At("RETURN")
)
private void postHandleBlockChange(SPacketBlockChange packetIn, CallbackInfo ci) {
if (!Baritone.settings().repackOnAnyBlockChange.value) {
return;
}
if (!CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(packetIn.getBlockState().getBlock())) {
return;
}
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
EntityPlayerSP player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
new ChunkEvent(
EventState.POST,
ChunkEvent.Type.POPULATE_FULL,
packetIn.getBlockPosition().getX() >> 4,
packetIn.getBlockPosition().getZ() >> 4
)
);
}
}
}
@Inject(
method = "handleMultiBlockChange",
at = @At("RETURN")
)
private void postHandleMultiBlockChange(SPacketMultiBlockChange packetIn, CallbackInfo ci) {
if (!Baritone.settings().repackOnAnyBlockChange.value) {
return;
}
if (packetIn.getChangedBlocks().length == 0) {
return;
}
https://docs.oracle.com/javase/specs/jls/se7/html/jls-14.html#jls-14.15
{
for (SPacketMultiBlockChange.BlockUpdateData update : packetIn.getChangedBlocks()) {
if (CachedChunk.BLOCKS_TO_KEEP_TRACK_OF.contains(update.getBlockState().getBlock())) {
break https;
}
}
return;
}
ChunkPos pos = new ChunkPos(packetIn.getChangedBlocks()[0].getPos());
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
EntityPlayerSP player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) {
ibaritone.getGameEventHandler().onChunkEvent(
new ChunkEvent(
EventState.POST,
ChunkEvent.Type.POPULATE_FULL,
pos.x,
pos.z
)
);
}
}
}
@Inject(
method = "handleCombatEvent",
at = @At(
@@ -86,7 +156,8 @@ public class MixinNetHandlerPlayClient {
)
private void onPlayerDeath(SPacketCombatEvent packetIn, CallbackInfo ci) {
for (IBaritone ibaritone : BaritoneAPI.getProvider().getAllBaritones()) {
if (ibaritone.getPlayerContext().player().connection == (NetHandlerPlayClient) (Object) this) {
EntityPlayerSP player = ibaritone.getPlayerContext().player();
if (player != null && player.connection == (NetHandlerPlayClient) (Object) this) {
ibaritone.getGameEventHandler().onPlayerDeath();
}
}

View File

@@ -24,12 +24,16 @@ import baritone.api.event.listener.IEventBus;
import baritone.api.utils.Helper;
import baritone.api.utils.IPlayerContext;
import baritone.behavior.*;
import baritone.builder.Main;
import baritone.cache.WorldProvider;
import baritone.command.manager.CommandManager;
import baritone.event.GameEventHandler;
import baritone.process.*;
import baritone.selection.SelectionManager;
import baritone.utils.*;
import baritone.command.manager.CommandManager;
import baritone.utils.BlockStateInterface;
import baritone.utils.GuiClick;
import baritone.utils.InputOverrideHandler;
import baritone.utils.PathingControlManager;
import baritone.utils.player.PrimaryPlayerContext;
import net.minecraft.client.Minecraft;
@@ -104,22 +108,27 @@ public class Baritone implements IBaritone {
this.pathingControlManager = new PathingControlManager(this);
{
followProcess = new FollowProcess(this);
mineProcess = new MineProcess(this);
customGoalProcess = new CustomGoalProcess(this); // very high iq
getToBlockProcess = new GetToBlockProcess(this);
builderProcess = new BuilderProcess(this);
exploreProcess = new ExploreProcess(this);
backfillProcess = new BackfillProcess(this);
farmProcess = new FarmProcess(this);
this.pathingControlManager.registerProcess(followProcess = new FollowProcess(this));
this.pathingControlManager.registerProcess(mineProcess = new MineProcess(this));
this.pathingControlManager.registerProcess(customGoalProcess = new CustomGoalProcess(this)); // very high iq
this.pathingControlManager.registerProcess(getToBlockProcess = new GetToBlockProcess(this));
this.pathingControlManager.registerProcess(builderProcess = new BuilderProcess(this));
this.pathingControlManager.registerProcess(exploreProcess = new ExploreProcess(this));
this.pathingControlManager.registerProcess(backfillProcess = new BackfillProcess(this));
this.pathingControlManager.registerProcess(farmProcess = new FarmProcess(this));
}
this.worldProvider = new WorldProvider();
this.selectionManager = new SelectionManager(this);
this.commandManager = new CommandManager(this);
if (BaritoneAutoTest.ENABLE_AUTO_TEST) {
this.gameEventHandler.registerEventListener(BaritoneAutoTest.INSTANCE);
try {
Main.main();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (Throwable th) {
th.printStackTrace();
throw th;
}
}

View File

@@ -22,9 +22,9 @@ import baritone.api.IBaritoneProvider;
import baritone.api.cache.IWorldScanner;
import baritone.api.command.ICommandSystem;
import baritone.api.schematic.ISchematicSystem;
import baritone.command.BaritoneChatControl;
import baritone.cache.WorldScanner;
import baritone.command.CommandSystem;
import baritone.command.ExampleBaritoneControl;
import baritone.utils.schematic.SchematicSystem;
import java.util.Collections;
@@ -44,7 +44,7 @@ public final class BaritoneProvider implements IBaritoneProvider {
this.all = Collections.singletonList(this.primary);
// Setup chat control, just for the primary instance
new BaritoneChatControl(this.primary);
new ExampleBaritoneControl(this.primary);
}
@Override

View File

@@ -0,0 +1,21 @@
/*
* 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;
// Annotation for classes and class members that should not be renamed by proguard
public @interface KeepName {}

View File

@@ -18,6 +18,7 @@
package baritone.behavior;
import baritone.Baritone;
import baritone.api.BaritoneAPI;
import baritone.api.event.events.TickEvent;
import baritone.utils.ToolSet;
import net.minecraft.block.Block;
@@ -112,6 +113,9 @@ public final class InventoryBehavior extends Behavior {
if (stack.isEmpty()) {
continue;
}
if (Baritone.settings().itemSaver.value && (stack.getItemDamage() + Baritone.settings().itemSaverThreshold.value) >= stack.getMaxDamage() && stack.getMaxDamage() > 1) {
continue;
}
if (cla$$.isInstance(stack.getItem())) {
double speed = ToolSet.calculateSpeedVsBlock(stack, against.getDefaultState()); // takes into account enchants
if (speed > bestSpeed) {
@@ -149,6 +153,10 @@ public final class InventoryBehavior extends Behavior {
}
public boolean throwaway(boolean select, Predicate<? super ItemStack> desired) {
return throwaway(select, desired, Baritone.settings().allowInventory.value);
}
public boolean throwaway(boolean select, Predicate<? super ItemStack> desired, boolean allowInventory) {
EntityPlayerSP p = ctx.player();
NonNullList<ItemStack> inv = p.inventory.mainInventory;
for (int i = 0; i < 9; i++) {
@@ -181,6 +189,19 @@ public final class InventoryBehavior extends Behavior {
}
}
}
if (allowInventory) {
for (int i = 9; i < 36; i++) {
if (desired.test(inv.get(i))) {
swapWithHotBar(i, 7);
if (select) {
p.inventory.currentItem = 7;
}
return true;
}
}
}
return false;
}
}

View File

@@ -25,6 +25,7 @@ import baritone.api.event.events.PlayerUpdateEvent;
import baritone.api.event.events.TickEvent;
import baritone.api.event.events.type.EventState;
import baritone.api.utils.BetterBlockPos;
import baritone.api.utils.Helper;
import baritone.cache.ContainerMemory;
import baritone.utils.BlockStateInterface;
import net.minecraft.block.Block;
@@ -40,13 +41,20 @@ import net.minecraft.tileentity.TileEntity;
import net.minecraft.tileentity.TileEntityLockable;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TextComponentString;
import net.minecraft.util.text.TextComponentTranslation;
import net.minecraft.util.text.TextFormatting;
import net.minecraft.util.text.event.ClickEvent;
import net.minecraft.util.text.event.HoverEvent;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.*;
import static baritone.api.command.IBaritoneChatControl.FORCE_COMMAND_PREFIX;
/**
* doesn't work for horse inventories :^)
*
@@ -166,7 +174,26 @@ public final class MemoryBehavior extends Behavior {
@Override
public void onPlayerDeath() {
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet()));
Waypoint deathWaypoint = new Waypoint("death", Waypoint.Tag.DEATH, ctx.playerFeet());
baritone.getWorldProvider().getCurrentWorld().getWaypoints().addWaypoint(deathWaypoint);
ITextComponent component = new TextComponentString("Death position saved.");
component.getStyle()
.setColor(TextFormatting.WHITE)
.setHoverEvent(new HoverEvent(
HoverEvent.Action.SHOW_TEXT,
new TextComponentString("Click to goto death")
))
.setClickEvent(new ClickEvent(
ClickEvent.Action.RUN_COMMAND,
String.format(
"%s%s goto %s @ %d",
FORCE_COMMAND_PREFIX,
"wp",
deathWaypoint.getTag().getName(),
deathWaypoint.getCreationTimestamp()
)
));
Helper.HELPER.logDirect(component);
}

View File

@@ -52,6 +52,10 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
private Goal goal;
private CalculationContext context;
/*eta*/
private int ticksElapsedSoFar;
private BetterBlockPos startPosition;
private boolean safeToCancel;
private boolean pauseRequestedLastTick;
private boolean unpausedLastTick;
@@ -98,12 +102,13 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
expectedSegmentStart = pathStart();
baritone.getPathingControlManager().preTick();
tickPath();
ticksElapsedSoFar++;
dispatchEvents();
}
@Override
public void onPlayerSprintState(SprintStateEvent event) {
if (current != null) {
if (isPathing()) {
event.setState(current.isSprinting());
}
}
@@ -372,6 +377,40 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
return context;
}
public Optional<Double> estimatedTicksToGoal() {
BetterBlockPos currentPos = ctx.playerFeet();
if (goal == null || currentPos == null || startPosition == null) {
return Optional.empty();
}
if (goal.isInGoal(ctx.playerFeet())) {
resetEstimatedTicksToGoal();
return Optional.of(0.0);
}
if (ticksElapsedSoFar == 0) {
return Optional.empty();
}
double current = goal.heuristic(currentPos.x, currentPos.y, currentPos.z);
double start = goal.heuristic(startPosition.x, startPosition.y, startPosition.z);
if (current == start) {// can't check above because current and start can be equal even if currentPos and startPosition are not
return Optional.empty();
}
double eta = Math.abs(current - goal.heuristic()) * ticksElapsedSoFar / Math.abs(start - current);
return Optional.of(eta);
}
private void resetEstimatedTicksToGoal() {
resetEstimatedTicksToGoal(expectedSegmentStart);
}
private void resetEstimatedTicksToGoal(BlockPos start) {
resetEstimatedTicksToGoal(new BetterBlockPos(start));
}
private void resetEstimatedTicksToGoal(BetterBlockPos start) {
ticksElapsedSoFar = 0;
startPosition = start;
}
/**
* See issue #209
*
@@ -468,6 +507,7 @@ public final class PathingBehavior extends Behavior implements IPathingBehavior,
if (executor.get().getPath().positions().contains(expectedSegmentStart)) {
queuePathEvent(PathEvent.CALC_FINISHED_NOW_EXECUTING);
current = executor.get();
resetEstimatedTicksToGoal(start);
} else {
logDebug("Warning: discarding orphan path segment with incorrect start");
}

View File

@@ -0,0 +1,56 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
import baritone.api.utils.IPlayerContext;
/**
* 1/16th of a block
* <p>
* Why do this? Several reasons:
* <p>
* • No floating point inaccuracy. I got incredibly annoyed with simple stuff like >1 and <1 being randomly wrong. It helps with stuff like slab calculations, 0.5 block steps, etc
* <p>
* • It's obscenely fast
*/
public class Blip {
public static final int FULL_BLOCK = 16;
public static final double RATIO = 0.0625;
public static final int HALF_BLOCK = 8;
public static final int PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE = 28;
public static final int PLAYER_HEIGHT_SLIGHT_OVERESTIMATE = 29;
public static final int TWO_BLOCKS = 2 * FULL_BLOCK;
public static final int FEET_TO_EYE_APPROX = (int) (IPlayerContext.eyeHeight(false) / RATIO);
public static final int JUMP = 20; // 1.25
public static final int TALLEST_BLOCK = FULL_BLOCK + HALF_BLOCK; // 24, 1.5 blocks tall, the fence / wall has the highest collision box
public static double playerEyeFromFeetBlips(int feetBlips, boolean sneaking) {
return feetBlips * RATIO + IPlayerContext.eyeHeight(sneaking);
}
static {
double realPlayerHeight = 1.8;
if (PLAYER_HEIGHT_SLIGHT_OVERESTIMATE * RATIO <= realPlayerHeight || PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE * RATIO >= realPlayerHeight || PLAYER_HEIGHT_SLIGHT_OVERESTIMATE != PLAYER_HEIGHT_SLIGHT_UNDERESTIMATE + 1) {
throw new IllegalStateException();
}
if (FULL_BLOCK * RATIO != 1) {
throw new IllegalStateException();
}
}
}

View File

@@ -0,0 +1,38 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class BlockData {
private final BlockStateCachedData[] PER_STATE;
public BlockData(IBlockStateDataProvider provider) {
PER_STATE = provider.allNullable();
}
public BlockStateCachedData get(int state) {
return PER_STATE[state];
}
public List<BlockStateCachedData> getAllStates() {
return Collections.unmodifiableList(Arrays.asList(PER_STATE));
}
}

View File

@@ -0,0 +1,85 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
import java.util.Collections;
import java.util.List;
/**
* Information about an IBlockState
* <p>
* There will be exactly one of these per valid IBlockState in the game
*/
public final class BlockStateCachedData {
public final boolean fullyWalkableTop;
private final int collisionHeightBlips;
public final boolean isAir;
public final boolean collidesWithPlayer;
public final boolean mustSneakWhenPlacingAgainstMe;
public final List<BlockStatePlacementOption> placeMe; // list because of unknown size with no obvious indexing
public final PlaceAgainstData[] placeAgainstMe; // array because of fixed size with obvious indexing (no more than one per face, so, index per face)
public BlockStateCachedData(BlockStateCachedDataBuilder builder) {
builder.sanityCheck();
this.isAir = builder.isAir();
this.fullyWalkableTop = builder.isFullyWalkableTop();
this.collidesWithPlayer = builder.isCollidesWithPlayer();
if (collidesWithPlayer) {
this.collisionHeightBlips = builder.collisionHeightBlips();
} else {
this.collisionHeightBlips = -1;
}
this.mustSneakWhenPlacingAgainstMe = builder.isMustSneakWhenPlacingAgainstMe();
this.placeMe = Collections.unmodifiableList(builder.howCanIBePlaced());
this.placeAgainstMe = builder.placeAgainstMe();
}
public int collisionHeightBlips() {
if (Main.DEBUG && !collidesWithPlayer) { // confirmed and tested: when DEBUG is false, proguard removes this if in the first pass, then inlines the calls in the second pass, making this just as good as a field access in release builds
throw new IllegalStateException();
}
return collisionHeightBlips;
}
public boolean possibleAgainstMe(BlockStatePlacementOption placement) {
PlaceAgainstData against = againstMe(placement);
return against != null && possible(placement, against);
}
public PlaceAgainstData againstMe(BlockStatePlacementOption placement) {
return placeAgainstMe[placement.against.oppositeIndex];
}
public static boolean possible(BlockStatePlacementOption placement, PlaceAgainstData against) {
if (placement.against != against.against.opposite()) {
throw new IllegalArgumentException();
}
if (placement.against.vertical) {
return true;
}
return
(against.presentsAnOptionStrictlyInTheBottomHalfOfTheStandardVoxelPlane() && placement.half != Half.TOP) ||
(against.presentsAnOptionStrictlyInTheTopHalfOfTheStandardVoxelPlane() && placement.half != Half.BOTTOM);
}
}

View File

@@ -0,0 +1,326 @@
/*
* 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.builder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
public class BlockStateCachedDataBuilder {
// should all these be optionals? like maybe Boolean? that start as null? and each has to be set explicitly?
private boolean isAir;
private boolean canPlaceAgainstMe;
private boolean fullyWalkableTop;
private boolean collidesWithPlayer;
private boolean mustSneakWhenPlacingAgainstMe;
private boolean mustBePlacedBottomToTop;
/**
* Examples:
* <p>
* Upside down stairs must be placed against TOP
* <p>
* Bottom slabs must be placed against BOTTOM
* <p>
* Normal blocks must be placed against EITHER
*/
private Half mustBePlacedAgainst = Half.EITHER;
private Face playerMustBeHorizontalFacingInOrderToPlaceMe;
private Integer collisionHeightBlips;
private Face canOnlyPlaceAgainst;
/**
* Blocks that have a collision height lower than their placement bounding box height.
* aka snow layers and soul sand.
* e.g. soul sand only collides with the player 0.875 high, but the BLOCK is 1.000 high, i.e. you can place against it at height 0.9 even though the player stands at height 0.875
*/
private boolean fakeLessThanFullHeight;
private boolean placementLogicNotImplementedYet;
private Face playerMustBeEntityFacingInOrderToPlaceMe;
public BlockStateCachedDataBuilder() {
}
/**
* Really just air. This is a fully open block that won't collide with object mouse over raytrace.
*/
public BlockStateCachedDataBuilder setAir() {
isAir = true;
mustBePlacedAgainst = null;
return this;
}
public boolean isAir() {
return isAir;
}
/**
* does the top face of this block fully support the player from 0.0,0.0 to 1.0,1.0? true for most normal blocks. false for, for example, fences
*/
public BlockStateCachedDataBuilder fullyWalkableTop() {
fullyWalkableTop = true;
return this;
}
public boolean isFullyWalkableTop() {
return fullyWalkableTop;
}
/**
* The highest collision extension of this block possible
* <p>
* For example, should be 1 for stairs, even though part of the top face is really 0.5
* <p>
* Should be 1 for top slabs
* <p>
* Should be 1 for trapdoors because when they're open, they touch the top face of the voxel
*/
public BlockStateCachedDataBuilder collisionHeight(double y) {
for (int h = 0; h <= Blip.TALLEST_BLOCK; h++) { // max height of
if (y == h * Blip.RATIO) {
collisionHeightBlips = h;
return this;
}
}
throw new IllegalStateException();
}
public Integer collisionHeightBlips() { // e.g. slabs are 0.5, soul sand is 0.875, normal blocks are 1, fences are 1.5
return collisionHeightBlips;
}
public BlockStateCachedDataBuilder mustSneakWhenPlacingAgainstMe() {
mustSneakWhenPlacingAgainstMe = true;
return this;
}
public boolean isMustSneakWhenPlacingAgainstMe() {
return mustSneakWhenPlacingAgainstMe;
}
public BlockStateCachedDataBuilder canPlaceAgainstMe() {
canPlaceAgainstMe = true;
return this;
}
public boolean isCollidesWithPlayer() {
return collidesWithPlayer;
}
public BlockStateCachedDataBuilder collidesWithPlayer(boolean val) {
collidesWithPlayer = val;
return this;
}
public BlockStateCachedDataBuilder playerMustBeHorizontalFacingInOrderToPlaceMe(Face face) {
playerMustBeHorizontalFacingInOrderToPlaceMe = face;
return this;
}
public BlockStateCachedDataBuilder playerMustBeEntityFacingInOrderToPlaceMe(Face face) {
playerMustBeEntityFacingInOrderToPlaceMe = face;
return this;
}
public BlockStateCachedDataBuilder mustBePlacedAgainst(Half half) {
if (half == null) {
throw new IllegalArgumentException();
}
mustBePlacedAgainst = half;
return this;
}
public BlockStateCachedDataBuilder mustBePlacedBottomToTop() {
mustBePlacedBottomToTop = true;
return this;
}
public BlockStateCachedDataBuilder canOnlyPlaceAgainst(Face face) {
canOnlyPlaceAgainst = face;
return this;
}
public BlockStateCachedDataBuilder placementLogicNotImplementedYet() {
placementLogicNotImplementedYet = true;
return this;
}
public BlockStateCachedDataBuilder fakeLessThanFullHeight() {
fakeLessThanFullHeight = true;
return this;
}
public List<BlockStatePlacementOption> howCanIBePlaced() {
if (mustBePlacedAgainst == null || placementLogicNotImplementedYet) {
return Collections.emptyList();
}
List<BlockStatePlacementOption> ret = new ArrayList<>();
for (Face face : Face.VALUES) {
if (Main.STRICT_Y && face == Face.UP) {
continue; // TODO don't do this...
}
if (playerMustBeHorizontalFacingInOrderToPlaceMe == face.opposite()) { // obv, this won't happen if playerMustBeHorizontalFacing is null
continue;
}
if (playerMustBeEntityFacingInOrderToPlaceMe == face) {
continue;
}
if (mustBePlacedBottomToTop && face != Face.DOWN) {
continue;
}
if (canOnlyPlaceAgainst != null && face != canOnlyPlaceAgainst) {
continue;
}
Half overrideHalf = mustBePlacedAgainst;
if (face == Face.DOWN) {
if (mustBePlacedAgainst == Half.TOP) {
continue;
} else {
overrideHalf = Half.EITHER;
}
}
if (face == Face.UP) {
if (mustBePlacedAgainst == Half.BOTTOM) {
continue;
} else {
overrideHalf = Half.EITHER;
}
}
ret.add(BlockStatePlacementOption.get(face, overrideHalf, Optional.ofNullable(playerMustBeHorizontalFacingInOrderToPlaceMe), Optional.ofNullable(playerMustBeEntityFacingInOrderToPlaceMe)));
}
return ret;
}
public PlaceAgainstData[] placeAgainstMe() {
PlaceAgainstData[] data = new PlaceAgainstData[Face.NUM_FACES];
if (!canPlaceAgainstMe) {
return data;
}
for (int i = 0; i < Face.NUM_FACES; i++) {
data[i] = placeAgainstFace(Face.VALUES[i]);
}
return data;
}
protected PlaceAgainstData placeAgainstFace(Face face) {
// TODO this makes the stair/slab assumption that the same half is the mustBePlacedAgainst as the faces offered for placement... counterexample is daylight sensor
// note that this is actually correct behavior for stairs - you can place against the top half of a upside down stair and against the bottom half of a normal stair
if (mustBePlacedAgainst == Half.TOP && face == Face.DOWN) {
return null;
}
if (mustBePlacedAgainst == Half.BOTTOM && face == Face.UP) {
return null;
}
return new PlaceAgainstData(face, face.vertical ? Half.EITHER : mustBePlacedAgainst, mustSneakWhenPlacingAgainstMe);
}
/**
* The idea here is that I codify all my assumptions in one place instead of having ad hoc checks absolutely everywhere
* <p>
* Example: in PlayerPhysics, I made an assumption that a block will never have a collision block taller than 1.5 blocks (e.g. like a fence)
* When I wrote the code that assumed that, I also added a check here to make sure every block is like that.
* If, in some future update to Minecraft, mojang adds a block that's even taller than a fence, it will be caught here immediately, with a comment saying "playerphysics assumes this is never true"
* This way, I'll know immediately, instead of pathing randomly trying to do something impossible with that new block and it being really confusing and annoying.
*/
public void sanityCheck() {
if (isAir()) {
if (!howCanIBePlaced().isEmpty()) {
throw new IllegalStateException();
}
if (isFullyWalkableTop()) {
throw new IllegalStateException();
}
if (collidesWithPlayer) {
throw new IllegalStateException();
}
}
if (mustBePlacedAgainst == null ^ isAir()) {
throw new IllegalStateException();
}
if (howCanIBePlaced().isEmpty()) {
if (mustBePlacedAgainst != null && !placementLogicNotImplementedYet) {
throw new IllegalStateException();
}
if (playerMustBeHorizontalFacingInOrderToPlaceMe != null || playerMustBeEntityFacingInOrderToPlaceMe != null) {
throw new IllegalStateException();
}
if (canOnlyPlaceAgainst != null) {
throw new IllegalStateException();
}
}
if (isMustSneakWhenPlacingAgainstMe() && mustBePlacedAgainst != Half.EITHER) {
throw new IllegalArgumentException();
}
if ((playerMustBeHorizontalFacingInOrderToPlaceMe != null || playerMustBeEntityFacingInOrderToPlaceMe != null) && mustBePlacedAgainst == null) {
throw new IllegalStateException();
}
if (collisionHeightBlips != null && (collisionHeightBlips > Blip.TALLEST_BLOCK || collisionHeightBlips < 0)) { // playerphysics assumes this is never true
throw new IllegalStateException();
}
if (collidesWithPlayer ^ collisionHeightBlips != null) {
throw new IllegalStateException();
}
if (fullyWalkableTop && !collidesWithPlayer) {
throw new IllegalStateException();
}
if (canPlaceAgainstMe && !collidesWithPlayer) {
throw new IllegalStateException();
}
if (playerMustBeHorizontalFacingInOrderToPlaceMe != null && playerMustBeHorizontalFacingInOrderToPlaceMe.vertical) {
throw new IllegalStateException();
}
if (Main.STRICT_Y && howCanIBePlaced().stream().anyMatch(opt -> opt.against == Face.UP)) {
throw new IllegalStateException();
}
PlaceAgainstData[] data = placeAgainstMe();
if (data.length != Face.NUM_FACES) {
throw new IllegalStateException();
}
boolean any = false;
for (int i = 0; i < Face.NUM_FACES; i++) {
if (data[i] != null) {
if (data[i].against != Face.VALUES[i]) {
throw new IllegalStateException();
}
if (!canPlaceAgainstMe) {
throw new IllegalStateException();
}
any = true;
}
}
if (canPlaceAgainstMe && !any) {
throw new IllegalStateException();
}
if (collisionHeightBlips != null && !fakeLessThanFullHeight) {
for (PlaceAgainstData d : data) {
if (d == null) {
continue;
}
d.streamRelativeToMyself().forEach(hit -> {
if (hit.y > collisionHeightBlips * Blip.RATIO) {
throw new IllegalStateException(d.against + " " + hit.y + " " + collisionHeightBlips * Blip.RATIO);
}
});
}
}
}
static {
new BlockStateCachedDataBuilder().sanityCheck();
}
}

View File

@@ -0,0 +1,236 @@
/*
* 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.builder;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.function.Supplier;
import java.util.stream.Collectors;
/**
* A plane against which this block state can be placed
* <p>
* For a normal block, this will be a full face of a block. In that case, this class is no more than an EnumFacing
* <p>
* For a block like a slab or a stair, this will contain the information that the placement must be against the top or bottom half of the face
* <p>
* For a block like a furnace, this will contain the information that the player must be facing a specific horizontal direction in order to get the desired orientation
* <p>
* For a block like a piston, dispenser, or observer, this will contain the information that be player must pass a combination of: specific relative eye coordinate, specific relative X Z, and specific horizontal facing
*/
public class BlockStatePlacementOption {
/**
* e.g. a torch placed down on the ground is placed against the bottom of "the torch bounding box", so this would be DOWN for the torch
*/
public final Face against;
public final Half half;
public final Optional<Face> playerMustBeHorizontalFacing; // getHorizontalFacing
/**
* IMPORTANT this is the RAW getDirectionFromEntityLiving meaning that it is the OPPOSITE of getHorizontalFacing (when in the horizontal plane)
*/
public final Optional<Face> playerMustBeEntityFacing; // EnumFacing.getDirectionFromEntityLiving, used by piston, dispenser, observer
private BlockStatePlacementOption(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
Objects.requireNonNull(against);
Objects.requireNonNull(half);
this.against = against;
this.half = half;
this.playerMustBeHorizontalFacing = playerMustBeHorizontalFacing;
this.playerMustBeEntityFacing = playerMustBeEntityFacing;
validate(against, half, playerMustBeHorizontalFacing, playerMustBeEntityFacing);
}
/**
* This value must be greater than the face projections.
* <p>
* Otherwise certain stair placements would not work. This is verified in the test
*/
public static final double LOOSE_CENTER_DISTANCE = 0.15;
public List<Raytracer.Raytrace> computeTraceOptions(PlaceAgainstData placingAgainst, int playerSupportingX, int playerFeetBlips, int playerSupportingZ, PlayerVantage vantage, double blockReachDistance) {
if (!BlockStateCachedData.possible(this, placingAgainst)) {
throw new IllegalStateException();
}
if (Main.DEBUG && placingAgainst.streamRelativeToPlace().noneMatch(hit -> hitOk(half, hit))) {
throw new IllegalStateException();
}
List<Vec2d> acceptableVantages = new ArrayList<>();
Vec2d center = Vec2d.HALVED_CENTER.plus(playerSupportingX, playerSupportingZ);
switch (vantage) {
case LOOSE_CENTER: {
acceptableVantages.add(center.plus(LOOSE_CENTER_DISTANCE, 0));
acceptableVantages.add(center.plus(-LOOSE_CENTER_DISTANCE, 0));
acceptableVantages.add(center.plus(0, LOOSE_CENTER_DISTANCE));
acceptableVantages.add(center.plus(0, -LOOSE_CENTER_DISTANCE));
// no break!
} // FALLTHROUGH!
case STRICT_CENTER: {
acceptableVantages.add(center);
break;
}
case SNEAK_BACKPLACE: {
if (playerSupportingX != against.x || playerSupportingZ != against.z) {
throw new IllegalStateException();
}
// in a sneak backplace, there is exactly one location where the player will be
acceptableVantages.add(Vec2d.HALVED_CENTER.plus(0.25 * against.x, 0.25 * against.z));
break;
}
default:
throw new IllegalStateException();
}
// direction from placed block to place-against block = this.against
long blockPlacedAt = 0;
long placeAgainstPos = against.offset(blockPlacedAt);
return sanityCheckTraces(acceptableVantages
.stream()
.map(playerEyeXZ -> new Vec3d(playerEyeXZ.x, Blip.playerEyeFromFeetBlips(playerFeetBlips, placingAgainst.mustSneak), playerEyeXZ.z))
.flatMap(eye ->
placingAgainst.streamRelativeToPlace()
.filter(hit -> hitOk(half, hit))
.filter(hit -> eye.distSq(hit) < blockReachDistance * blockReachDistance)
.filter(hit -> directionOk(eye, hit))
.<Supplier<Optional<Raytracer.Raytrace>>>map(hit -> () -> Raytracer.runTrace(eye, placeAgainstPos, against.opposite(), hit))
)
.collect(Collectors.toList())
.parallelStream() // wrap it like this because flatMap forces .sequential() on the interior child stream, defeating the point
.map(Supplier::get)
.filter(Optional::isPresent)
.map(Optional::get)
.sorted()
.collect(Collectors.toList()));
}
public static boolean hitOk(Half half, Vec3d hit) {
if (half == Half.EITHER) {
return true;
} else if (hit.y == 0.1) {
return half == Half.BOTTOM;
} else if (hit.y == 0.5) {
return false; // ambiguous, so force it to pick either down or up
} else if (hit.y == 0.9) {
return half == Half.TOP;
} else {
throw new IllegalStateException();
}
}
/**
* In EnumFacing.getDirectionFromEntityLiving, it checks if the player feet is within 2 blocks of the center of the block to be placed.
* Normally, this is a nonissue, but a problem arises because we are considering hypothetical placements where the player stands at the exact +0.5,+0.5 center of a block.
* In that case, it's possible for our hypothetical to have the player at precisely 2 blocks away, i.e. precisely on the edge of this condition being true or false.
* For that reason, we treat those exact cases as "ambiguous". So, if the distance is within this tolerance of 2 (so, 1.99 to 2.01), we treat it as a "could go either way",
* because when we really get there in-game, floating point inaccuracy could indeed actually make it go either way.
*/
private static final double ENTITY_FACING_TOLERANCE = 0.01;
private boolean directionOk(Vec3d eye, Vec3d hit) {
if (playerMustBeHorizontalFacing.isPresent()) {
return eye.flatDirectionTo(hit) == playerMustBeHorizontalFacing.get();
}
if (playerMustBeEntityFacing.isPresent()) { // handle piston, dispenser, dropper, observer
if (!hit.inOriginUnitVoxel()) {
throw new IllegalStateException();
}
Face entFace = playerMustBeEntityFacing.get();
// see EnumFacing.getDirectionFromEntityLiving
double dx = Math.abs(eye.x - 0.5); // TODO this is changed between 1.12 and 1.19, in 1.19 this should be eye.x-hit.x
double dz = Math.abs(eye.z - 0.5);
if (dx < 2 - ENTITY_FACING_TOLERANCE && dz < 2 - ENTITY_FACING_TOLERANCE) { // < 1.99
if (eye.y < 0) { // eye below placement level = it will be facing down, so this is only okay if we want that
return entFace == Face.DOWN;
}
if (eye.y > 2) { // same for up, if y>2 then it will be facing up
return entFace == Face.UP;
}
} else if (!(dx > 2 + ENTITY_FACING_TOLERANCE || dz > 2 + ENTITY_FACING_TOLERANCE)) { // > 2.01
// this is the ambiguous case, because we are neither unambiguously both-within-2 (previous case), nor unambiguously either-above-two (this elseif condition).
// UP/DOWN are impossible, but that's caught by flat check
if (eye.y < 0 || eye.y > 2) { // this check is okay because player eye height is not an even multiple of blips, therefore there's no way for it to == 0 or == 2, so using > and < is safe
return false; // anything that could cause up/down instead of horizontal is also not allowed sadly
}
} // else we are in unambiguous either-above-two, putting us in simple horizontal mode, so fallthrough to flat condition is correct, yay
return eye.flatDirectionTo(hit) == entFace.opposite();
}
return true;
}
public static BlockStatePlacementOption get(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
BlockStatePlacementOption ret = PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][Face.OPTS.indexOf(playerMustBeHorizontalFacing)][Face.OPTS.indexOf(playerMustBeEntityFacing)];
if (ret == null) {
throw new IllegalStateException(against + " " + half + " " + playerMustBeHorizontalFacing + " " + playerMustBeEntityFacing);
}
return ret;
}
private static final BlockStatePlacementOption[][][][] PLACEMENT_OPTION_SINGLETON_CACHE;
static {
PLACEMENT_OPTION_SINGLETON_CACHE = new BlockStatePlacementOption[Face.NUM_FACES][Half.values().length][Face.OPTS.size()][Face.OPTS.size()];
for (Face against : Face.VALUES) {
for (Half half : Half.values()) {
for (Optional<Face> horizontalFacing : Face.OPTS) {
for (Optional<Face> entityFacing : Face.OPTS) {
try {
PLACEMENT_OPTION_SINGLETON_CACHE[against.index][half.ordinal()][Face.OPTS.indexOf(horizontalFacing)][Face.OPTS.indexOf(entityFacing)] = new BlockStatePlacementOption(against, half, horizontalFacing, entityFacing);
} catch (RuntimeException ex) {}
}
}
}
}
}
private void validate(Face against, Half half, Optional<Face> playerMustBeHorizontalFacing, Optional<Face> playerMustBeEntityFacing) {
if (playerMustBeEntityFacing.isPresent() && playerMustBeHorizontalFacing.isPresent()) {
throw new IllegalStateException();
}
if (against.vertical && half != Half.EITHER) {
throw new IllegalArgumentException();
}
if (Main.STRICT_Y && against == Face.UP) {
throw new IllegalStateException();
}
playerMustBeHorizontalFacing.ifPresent(face -> {
if (face.vertical) {
throw new IllegalArgumentException();
}
if (face == against.opposite()) {
throw new IllegalStateException();
}
});
playerMustBeEntityFacing.ifPresent(face -> {
if (half != Half.EITHER) {
throw new IllegalStateException();
}
if (against == face) { // impossible because EnumFacing inverts the horizontal facing AND because the down and up require the eye to be <0 and >2 respectively
throw new IllegalStateException();
}
});
}
private static List<Raytracer.Raytrace> sanityCheckTraces(List<Raytracer.Raytrace> traces) {
if (Main.DEBUG && traces.stream().mapToDouble(Raytracer.Raytrace::centerDistApprox).distinct().count() > 2) {
throw new IllegalStateException();
}
return traces;
}
}

View File

@@ -0,0 +1,98 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.LongArrayFIFOQueue;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
/**
* An area.
* <p>
* More likely than not a cuboid, but who knows :)
*/
public interface Bounds {
@FunctionalInterface
interface BoundsIntsConsumer {
void consume(int x, int y, int z);
}
@FunctionalInterface
interface BoundsLongConsumer {
void consume(long pos);
}
@FunctionalInterface
interface BoundsIntAndLongConsumer {
void consume(int x, int y, int z, long pos);
}
void forEach(BoundsIntsConsumer consumer);
void forEach(BoundsLongConsumer consumer);
void forEach(BoundsIntAndLongConsumer consumer);
// there is no "forEach" for the "index" lookup, because it is always going to just be a loop from 0 to bounds.volume()-1
boolean inRange(int x, int y, int z);
default boolean inRangePos(long pos) {
return inRange(BetterBlockPos.XfromLong(pos), BetterBlockPos.YfromLong(pos), BetterBlockPos.ZfromLong(pos));
}
int volume();
// this must be implemented EXTREMELY efficiently. no integer division allowed! even a hashmap lookup is borderline.
int toIndex(int x, int y, int z); // easy to implement for cuboid, harder for more complicated shapes
default int toIndex(long pos) {
return toIndex(BetterBlockPos.XfromLong(pos), BetterBlockPos.YfromLong(pos), BetterBlockPos.ZfromLong(pos));
}
static void sanityCheckConnectedness(Bounds bounds) {
LongOpenHashSet all = new LongOpenHashSet();
bounds.forEach(all::add);
if (all.size() != bounds.volume()) {
throw new IllegalStateException();
}
long any = all.iterator().nextLong();
LongOpenHashSet reachable = new LongOpenHashSet();
LongArrayFIFOQueue queue = new LongArrayFIFOQueue();
queue.enqueue(any);
while (!queue.isEmpty()) {
long pos = queue.dequeueLong();
if (bounds.inRangePos(pos) && reachable.add(pos)) {
for (Face face : Face.VALUES) {
queue.enqueueFirst(face.offset(pos));
}
}
}
LongIterator it = all.iterator();
while (it.hasNext()) {
if (!reachable.contains(it.nextLong())) {
throw new IllegalStateException();
}
}
}
}

View File

@@ -0,0 +1,120 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import java.util.stream.IntStream;
import static baritone.api.utils.BetterBlockPos.Y_MASK;
import static baritone.api.utils.BetterBlockPos.Y_SHIFT;
/**
* A mutable class representing a 1x6x1 column of blocks
* <p>
* Mutable because allocations are not on the table for the core solver loop
*/
public class Column {
public long pos; // TODO this isn't set?
//public BlockStateCachedData underUnderneath;
public BlockStateCachedData underneath;
public BlockStateCachedData feet;
public BlockStateCachedData head;
public BlockStateCachedData above;
public BlockStateCachedData aboveAbove;
public PlayerPhysics.VoxelResidency voxelResidency;
public Integer feetBlips;
public void initFrom(long pos, WorldState worldState, SolverEngineInput engineInput) {
this.pos = pos;
//this.underUnderneath = engineInput.at((pos + DOWN_2) & BetterBlockPos.POST_ADDITION_MASK, worldState);
this.underneath = engineInput.at((pos + DOWN_1) & BetterBlockPos.POST_ADDITION_MASK, worldState);
this.feet = engineInput.at(pos, worldState);
this.head = engineInput.at((pos + UP_1) & BetterBlockPos.POST_ADDITION_MASK, worldState);
this.above = engineInput.at((pos + UP_2) & BetterBlockPos.POST_ADDITION_MASK, worldState);
this.aboveAbove = engineInput.at((pos + UP_3) & BetterBlockPos.POST_ADDITION_MASK, worldState);
init();
}
public void init() {
this.voxelResidency = PlayerPhysics.canPlayerStand(underneath, feet);
this.feetBlips = boxNullable(PlayerPhysics.determinePlayerRealSupportLevel(underneath, feet, voxelResidency));
if (feetBlips != null && !playerCanExistAtFootBlip(feetBlips)) { // TODO is this the correct way to handle head collision?
voxelResidency = PlayerPhysics.VoxelResidency.IMPOSSIBLE_WITHOUT_SUFFOCATING; // TODO this is a misuse of this enum value i think
feetBlips = null;
}
}
public boolean playerCanExistAtFootBlip(int blipWithinFeet) {
if (head.collidesWithPlayer) {
return false;
}
if (PlayerPhysics.protrudesIntoThirdBlock(blipWithinFeet) && above.collidesWithPlayer) {
return false;
}
return true;
}
public boolean okToSneakIntoHereAtHeight(int blips) {
return playerCanExistAtFootBlip(blips) // no collision at head level
&& PlayerPhysics.highestCollision(underneath, feet) < blips; // and at foot level, we only collide strictly below where the feet will be
}
public boolean standing() {
return feetBlips != null;
}
public static final long DOWN_3 = (Y_MASK - 2) << Y_SHIFT;
public static final long DOWN_2 = (Y_MASK - 1) << Y_SHIFT;
public static final long DOWN_1 = Y_MASK << Y_SHIFT;
public static final long UP_1 = 1L << Y_SHIFT;
public static final long UP_2 = 2L << Y_SHIFT;
public static final long UP_3 = 3L << Y_SHIFT;
static {
if (DOWN_3 != BetterBlockPos.toLong(0, -3, 0)) {
throw new IllegalStateException();
}
if (DOWN_2 != BetterBlockPos.toLong(0, -2, 0)) {
throw new IllegalStateException();
}
if (DOWN_1 != BetterBlockPos.toLong(0, -1, 0)) {
throw new IllegalStateException();
}
if (UP_1 != BetterBlockPos.toLong(0, 1, 0)) {
throw new IllegalStateException();
}
if (UP_2 != BetterBlockPos.toLong(0, 2, 0)) {
throw new IllegalStateException();
}
if (UP_3 != BetterBlockPos.toLong(0, 3, 0)) {
throw new IllegalStateException();
}
}
private static final Integer[] BLIPS = IntStream.range(-1, Blip.FULL_BLOCK).boxed().toArray(Integer[]::new);
static {
BLIPS[0] = null;
}
private static Integer boxNullable(int blips) {
return BLIPS[blips + 1]; // map -1 to [0] which is null
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import java.util.OptionalInt;
public class CountingSurface extends NavigableSurface {
public CountingSurface(int x, int y, int z) {
super(x, y, z, Attachment::new, $ -> new Attachment());
}
private static class Attachment {
public final int surfaceSize;
public Attachment(Object a, Object b) {
this((Attachment) a, (Attachment) b);
}
public Attachment(Attachment a, Attachment b) {
this.surfaceSize = a.surfaceSize + b.surfaceSize;
}
public Attachment() {
this.surfaceSize = 1;
}
@Override
public boolean equals(Object o) { // used as performance optimization in RedBlackNode to avoid augmenting unchanged attachments
if (this == o) {
return true;
}
if (!(o instanceof Attachment)) {
return false;
}
Attachment that = (Attachment) o;
return surfaceSize == that.surfaceSize;
}
@Override
public int hashCode() {
return surfaceSize;
}
}
public OptionalInt surfaceSize(BetterBlockPos pos) { // how big is the navigable surface from here? how many distinct coordinates can i walk to (in the future, the augmentation will probably have a list of those coordinates or something?)
Object data = getComponentAugmentation(pos);
if (data != null) { // i disagree with the intellij suggestion here i think it makes it worse
return OptionalInt.of(((Attachment) data).surfaceSize);
} else {
return OptionalInt.empty();
}
}
public int requireSurfaceSize(int x, int y, int z) {
return surfaceSize(new BetterBlockPos(x, y, z)).getAsInt();
}
private void placeOrRemoveBlock(BetterBlockPos where, boolean place) {
setBlock(where.toLong(), place ? FakeStates.SOLID : FakeStates.AIR);
}
public void placeBlock(BetterBlockPos where) {
placeOrRemoveBlock(where, true);
}
public void placeBlock(int x, int y, int z) {
placeBlock(new BetterBlockPos(x, y, z));
}
public void removeBlock(BetterBlockPos where) {
placeOrRemoveBlock(where, false);
}
public void removeBlock(int x, int y, int z) {
removeBlock(new BetterBlockPos(x, y, z));
}
}

View File

@@ -0,0 +1,165 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
/**
* Bounding box of a cuboid
* <p>
* Basically just a lot of helper util methods lol
*/
public class CuboidBounds implements Bounds {
public final int sizeX;
public final int sizeY;
public final int sizeZ;
private final int sizeXMinusOne;
private final int sizeYMinusOne;
private final int sizeZMinusOne;
public final int size;
private final int sizeMinusOne;
public CuboidBounds(int sizeX, int sizeY, int sizeZ) {
this.sizeX = sizeX;
this.sizeY = sizeY;
this.sizeZ = sizeZ;
this.sizeXMinusOne = sizeX - 1;
this.sizeYMinusOne = sizeY - 1;
this.sizeZMinusOne = sizeZ - 1;
this.size = sizeX * sizeY * sizeZ;
this.sizeMinusOne = size - 1;
if (Main.SLOW_DEBUG) {
sanityCheck();
}
}
@Override
public int toIndex(int x, int y, int z) {
if (Main.DEBUG && !inRange(x, y, z)) {
throw new IllegalStateException();
}
return (x * sizeY + y) * sizeZ + z;
}
@Override
public boolean inRange(int x, int y, int z) {
return inRangeBranchless(x, y, z);
}
@Override
public int volume() {
return size;
}
@Deprecated
public boolean inRangeBranchy(int x, int y, int z) { // benchmarked: approx 4x slower than branchless
return (x >= 0) && (x < sizeX) && (y >= 0) && (y < sizeY) && (z >= 0) && (z < sizeZ);
}
public boolean inRangeBranchless(int x, int y, int z) {
return (x | y | z | (sizeXMinusOne - x) | (sizeYMinusOne - y) | (sizeZMinusOne - z)) >= 0;
}
public boolean inRangeBranchless2(int x, int y, int z) {
return (x | y | z | ((sizeX - 1) - x) | ((sizeY - 1) - y) | ((sizeZ - 1) - z)) >= 0;
}
public boolean inRangeBranchless3(int x, int y, int z) {
return (x | y | z | (sizeX - (x + 1)) | (sizeY - (y + 1)) | (sizeZ - (z + 1))) >= 0;
}
public boolean inRangeBranchless4(int x, int y, int z) {
return (x | y | z | ((sizeX - x) - 1) | ((sizeY - y) - 1) | ((sizeZ - z) - 1)) >= 0;
}
public boolean inRangeIndex(int index) {
return (index | (sizeMinusOne - index)) >= 0;
}
@Override
public void forEach(BoundsIntsConsumer consumer) {
int sizeX = this.sizeX, sizeY = this.sizeY, sizeZ = this.sizeZ;
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
consumer.consume(x, y, z);
}
}
}
}
@Override
public void forEach(BoundsLongConsumer consumer) {
int sizeX = this.sizeX, sizeY = this.sizeY, sizeZ = this.sizeZ;
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
consumer.consume(BetterBlockPos.toLong(x, y, z));
}
}
}
}
@Override
public void forEach(BoundsIntAndLongConsumer consumer) {
int sizeX = this.sizeX, sizeY = this.sizeY, sizeZ = this.sizeZ;
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
consumer.consume(x, y, z, BetterBlockPos.toLong(x, y, z));
}
}
}
}
public void sanityCheck() {
if (sizeY > 256) {
throw new IllegalStateException();
}
long chk = ((long) sizeX) * ((long) sizeY) * ((long) sizeZ);
if (chk != (long) size) {
throw new IllegalStateException();
}
int index = 0;
for (int x = 0; x < sizeX; x++) {
for (int y = 0; y < sizeY; y++) {
for (int z = 0; z < sizeZ; z++) {
if (!inRange(x, y, z)) {
throw new IllegalStateException();
}
if (toIndex(x, y, z) != index) {
throw new IllegalStateException();
}
index++;
}
}
}
if (index != size) {
throw new IllegalStateException();
}
if (inRange(-1, 0, 0) || inRange(0, -1, 0) || inRange(0, 0, -1)) {
throw new IllegalStateException();
}
if (inRange(sizeX, 0, 0) || inRange(0, sizeY, 0) || inRange(0, 0, sizeZ)) {
throw new IllegalStateException();
}
Bounds.sanityCheckConnectedness(this);
}
}

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.builder;
import baritone.api.utils.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.*;
import java.util.ArrayList;
import java.util.List;
/**
* Some initial checks on the schematic
* <p>
* The intent is to provide reasonable error messages, which we can do by catching common cases as early as possible
* <p>
* So that it's an actual comprehensible error **that tells you where the problem is** instead of just "pathing failed"
*/
public class DependencyGraphAnalyzer {
/**
* Just a simple check to make sure that everything is placeable.
* <p>
* Mostly for my own testing because every Minecraft block is placeable, and if the schematic has something weird
* and funky, it should be caught earlier anyway.
*/
public static void prevalidate(PlaceOrderDependencyGraph graph) {
List<String> locs = new ArrayList<>();
graph.bounds().forEach(pos -> {
if (graph.airTreatedAsScaffolding(pos)) {
// completely fine to, for example, have an air pocket with non-place-against-able stuff all around it
return;
}
for (Face face : Face.VALUES) {
if (graph.incomingEdge(pos, face)) {
return;
}
}
locs.add(BetterBlockPos.fromLong(pos).toString());
});
if (!locs.isEmpty()) {
throw new IllegalStateException("Unplaceable from any side: " + cuteTrim(locs));
}
// TODO instead of cuteTrim have a like SpecificBlockPositionsImpossibleException that this throws, and then later, an enclosing function can give the option to reset those locations to air
}
/**
* Search from all exterior nodes breadth-first to ensure that, theoretically, everything is reachable.
* <p>
* This is NOT a sufficient test, because later we are going to ensure that everything is scaffold-placeable which
* requires a single root node at the bottom.
*/
public static void prevalidateExternalToInteriorSearch(PlaceOrderDependencyGraph graph) {
LongList edgeBegins = new LongArrayList();
graph.bounds().forEach(pos -> {
for (Face face : Face.VALUES) {
if (graph.incomingEdgePermitExterior(pos, face) && !graph.incomingEdge(pos, face)) {
// this block is placeable from the exterior of the schematic!
edgeBegins.add(pos); // this will intentionally put the top of the schematic at the front
}
}
});
LongSet reachable = searchGraph(edgeBegins, graph::outgoingEdge);
List<String> locs = new ArrayList<>();
graph.bounds().forEach(pos -> {
if (graph.airTreatedAsScaffolding(pos)) {
// same as previous validation
return;
}
if (!reachable.contains(pos)) {
locs.add(BetterBlockPos.fromLong(pos).toString());
}
});
if (!locs.isEmpty()) {
throw new IllegalStateException("Placeable, in theory, but in practice there is no valid path from the exterior to it: " + cuteTrim(locs));
}
}
@FunctionalInterface
interface EdgeTester {
boolean hasEdge(long from, Face dir);
}
public static LongSet searchGraph(LongCollection origin, EdgeTester edgeTester) {
LongOpenHashSet reachable = new LongOpenHashSet();
LongArrayFIFOQueue queue = new LongArrayFIFOQueue(origin.size());
LongIterator it = origin.iterator();
while (it.hasNext()) {
queue.enqueue(it.nextLong());
}
while (!queue.isEmpty()) {
long pos = queue.dequeueLong();
if (reachable.add(pos)) {
for (Face face : Face.VALUES) {
if (edgeTester.hasEdge(pos, face)) {
queue.enqueueFirst(face.offset(pos));
}
}
}
}
return reachable;
}
private static List<String> cuteTrim(List<String> pos) {
if (pos.size() <= 20) {
return pos;
}
pos = pos.subList(0, 20);
pos.set(pos.size() - 1, "...");
return pos;
}
}

View File

@@ -0,0 +1,499 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectMaps;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.*;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.*;
/**
* A mutable addition of scaffolding blocks to a schematic
* <p>
* Contains a set of coordinates that are "air" in the schematic, but we are going to put scaffolding throwaway blocks there
* <p>
* Maintains and incrementally updates a collapsed dependency graph, which is the block placement dependency graph reduced to directed acyclic graph form by way of collapsing all strongly connected components into single nodes
* <p>
* Helper class, only intended to be used within Scaffolder
*/
public class DependencyGraphScaffoldingOverlay {
private final PlaceOrderDependencyGraph delegate;
private final LongOpenHashSet scaffoldingAdded;
private final CollapsedDependencyGraph collapsedGraph;
public DependencyGraphScaffoldingOverlay(PlaceOrderDependencyGraph delegate) {
this.delegate = delegate;
this.scaffoldingAdded = new LongOpenHashSet();
this.collapsedGraph = new CollapsedDependencyGraph(TarjansAlgorithm.run(this));
//System.out.println("Num components: " + collapsedGraph.components.size());
}
public boolean outgoingEdge(long pos, Face face) {
if (overrideOff(pos)) {
return false;
}
if (overrideOff(face.offset(pos))) {
return false;
}
return delegate.outgoingEdge(pos, face);
}
public boolean incomingEdge(long pos, Face face) {
if (overrideOff(pos)) {
return false;
}
if (overrideOff(face.offset(pos))) {
return false;
}
return delegate.incomingEdge(pos, face);
}
public boolean hypotheticalScaffoldingIncomingEdge(long pos, Face face) {
return delegate.incomingEdge(pos, face);
}
public Bounds bounds() {
return delegate.bounds();
}
private boolean overrideOff(long pos) {
return bounds().inRangePos(pos) && air(pos);
}
public boolean real(long pos) {
return !air(pos);
}
public void forEachReal(Bounds.BoundsLongConsumer consumer) {
bounds().forEach(pos -> {
if (real(pos)) {
consumer.consume(pos);
}
});
}
public boolean air(long pos) {
return delegate.airTreatedAsScaffolding(pos) && !scaffoldingAdded.contains(pos);
}
public void enable(long pos) {
if (!delegate.airTreatedAsScaffolding(pos)) {
throw new IllegalArgumentException();
}
if (!scaffoldingAdded.add(pos)) {
throw new IllegalArgumentException();
}
collapsedGraph.incrementalUpdate(pos);
if (Main.SLOW_DEBUG) {
//System.out.println(collapsedGraph.posToComponent.containsKey(pos) + " " + scaffoldingAdded.contains(pos) + " " + real(pos));
recheckEntireCollapsedGraph();
}
}
public void recheckEntireCollapsedGraph() {
checkEquality(collapsedGraph, new CollapsedDependencyGraph(TarjansAlgorithm.run(this)));
//System.out.println("Checked equality");
//System.out.println("Num connected components: " + collapsedGraph.components.size());
}
public LongSets.UnmodifiableSet scaffolding() {
return (LongSets.UnmodifiableSet) LongSets.unmodifiable(scaffoldingAdded);
}
public BlockStateCachedData data(long pos) {
if (Main.DEBUG && !real(pos)) {
throw new IllegalStateException();
}
return delegate.data(pos);
}
/**
* Remember that this returns a collapsed graph that will be updated in-place as positions are enabled. It does not return a copy.
*/
public CollapsedDependencyGraph getCollapsedGraph() {
return collapsedGraph;
}
public class CollapsedDependencyGraph {
private int nextComponentID;
private final Int2ObjectOpenHashMap<CollapsedDependencyGraphComponent> components;
private final Long2ObjectOpenHashMap<CollapsedDependencyGraphComponent> posToComponent;
private CollapsedDependencyGraph(TarjansAlgorithm.TarjansResult partition) {
components = new Int2ObjectOpenHashMap<>();
for (int i = 0; i < partition.numComponents(); i++) {
addComponent();
}
posToComponent = new Long2ObjectOpenHashMap<>();
forEachReal(pos -> {
CollapsedDependencyGraphComponent component = components.get(partition.getComponent(pos));
component.positions.add(pos);
posToComponent.put(pos, component);
});
forEachReal(pos -> {
for (Face face : Face.VALUES) {
if (outgoingEdge(pos, face)) {
CollapsedDependencyGraphComponent src = posToComponent.get(pos);
CollapsedDependencyGraphComponent dst = posToComponent.get(face.offset(pos));
if (src != dst) {
src.outgoingEdges.add(dst);
dst.incomingEdges.add(src);
}
}
}
});
if (Main.SLOW_DEBUG) {
sanityCheck();
}
}
public Int2ObjectMap<CollapsedDependencyGraphComponent> getComponents() {
return Int2ObjectMaps.unmodifiable(components);
}
public Long2ObjectMap<CollapsedDependencyGraphComponent> getComponentLocations() {
return Long2ObjectMaps.unmodifiable(posToComponent);
}
public OptionalInt lastComponentID() {
return nextComponentID == 0 ? OptionalInt.empty() : OptionalInt.of(nextComponentID - 1);
}
private CollapsedDependencyGraphComponent addComponent() {
CollapsedDependencyGraphComponent component = new CollapsedDependencyGraphComponent(nextComponentID);
components.put(component.id, component);
nextComponentID++;
return component;
}
private CollapsedDependencyGraphComponent mergeInto(CollapsedDependencyGraphComponent child, CollapsedDependencyGraphComponent parent) {
if (child.deleted() || parent.deleted()) {
throw new IllegalStateException();
}
if (child == parent) {
throw new IllegalStateException();
}
if (child.positions.size() > parent.positions.size() || (child.positions.size() == parent.positions.size() && child.id < parent.id)) {
return mergeInto(parent, child);
}
if (Main.DEBUG) {
//System.out.println("Merging " + child.index + " into " + parent.index);
}
child.incomingEdges.forEach(intoChild -> {
intoChild.outgoingEdges.remove(child);
if (intoChild == parent) {
return;
}
intoChild.outgoingEdges.add(parent);
parent.incomingEdges.add(intoChild);
});
child.outgoingEdges.forEach(outOfChild -> {
outOfChild.incomingEdges.remove(child);
if (outOfChild == parent) {
return;
}
outOfChild.incomingEdges.add(parent);
parent.outgoingEdges.add(outOfChild);
});
parent.positions.addAll(child.positions);
LongIterator it = child.positions.iterator();
while (it.hasNext()) {
long pos = it.nextLong();
posToComponent.put(pos, parent);
}
components.remove(child.id);
child.deletedInto = parent;
// TODO clear and trim child.positions? maybe unnecessary because nothing should retain a reference to child for longer than a moment
return parent;
}
private void incrementalEdgeAddition(long src, long dst) { // TODO put in a param here like "bias" that determines which of the two components gets to eat the other if they are of the same size? could help with the scaffolder if we could guarantee that no new components would be added without cause
CollapsedDependencyGraphComponent srcComponent = posToComponent.get(src);
CollapsedDependencyGraphComponent dstComponent = posToComponent.get(dst);
if (srcComponent == dstComponent) { // already strongly connected
return;
}
if (srcComponent.outgoingEdges.contains(dstComponent)) { // we already know about this edge
return;
}
List<List<CollapsedDependencyGraphComponent>> paths = new ArrayList<>();
if (!srcComponent.incomingEdges.isEmpty() && pathExists(dstComponent, srcComponent, paths) > 0) {
CollapsedDependencyGraphComponent survivor = srcComponent;
for (List<CollapsedDependencyGraphComponent> path : paths) {
if (path.get(0) != srcComponent || path.get(path.size() - 1) != dstComponent) {
throw new IllegalStateException();
}
for (int i = 1; i < path.size(); i++) {
if (path.get(i).deleted() || path.get(i) == survivor) { // two different paths to the same goal, only merge the components once, so skip is already survivor or deleted
continue;
}
survivor = mergeInto(survivor, path.get(i));
}
}
// can't run sanityCheck after each mergeInto because it could leave a 2-way connection between components as an intermediary state while collapsing
if (Main.SLOW_DEBUG) {
sanityCheck();
}
return;
}
srcComponent.outgoingEdges.add(dstComponent);
dstComponent.incomingEdges.add(srcComponent);
}
private int pathExists(CollapsedDependencyGraphComponent src, CollapsedDependencyGraphComponent dst, List<List<CollapsedDependencyGraphComponent>> paths) {
if (src == dst) {
paths.add(new ArrayList<>(Collections.singletonList(src)));
return 1;
}
if (Main.DEBUG && dst.incomingEdges.isEmpty()) {
throw new IllegalStateException();
}
if (Main.STRICT_Y && src.y() > dst.y()) {
return 0; // no downward edges in strict_y mode
}
int numAdded = 0;
for (CollapsedDependencyGraphComponent nxt : src.outgoingEdges) {
int cnt = pathExists(nxt, dst, paths);
if (cnt > 0) {
for (int i = 0; i < cnt; i++) {
paths.get(paths.size() - 1 - i).add(src);
}
numAdded += cnt;
}
}
return numAdded;
}
private void incrementalUpdate(long pos) {
if (posToComponent.containsKey(pos)) {
throw new IllegalStateException();
}
CollapsedDependencyGraphComponent component = addComponent();
component.positions.add(pos);
posToComponent.put(pos, component);
if (Main.SLOW_DEBUG) {
sanityCheck();
}
//System.out.println("Incremental " + pos);
//System.out.println("Pos core " + posToComponent.get(pos).index);
for (Face face : Face.VALUES) {
if (outgoingEdge(pos, face)) {
//System.out.println("Pos outgoing edge " + face + " goes to " + posToComponent.get(face.offset(pos)).index);
incrementalEdgeAddition(pos, face.offset(pos));
}
if (incomingEdge(pos, face)) {
//System.out.println("Pos incoming edge " + face + " comes from " + posToComponent.get(face.offset(pos)).index);
incrementalEdgeAddition(face.offset(pos), pos);
}
}
if (Main.SLOW_DEBUG) {
sanityCheck();
}
}
public class CollapsedDependencyGraphComponent {
private final int id;
private final int hash;
private final LongOpenHashSet positions = new LongOpenHashSet();
private final Set<CollapsedDependencyGraphComponent> outgoingEdges = new ObjectOpenHashSet<>();
private final Set<CollapsedDependencyGraphComponent> incomingEdges = new ObjectOpenHashSet<>();
// if i change ^^ that "Set" to "ObjectOpenHashSet" it actually makes the bench about 15% SLOWER?!?!?
private int y = -1;
private CollapsedDependencyGraphComponent deletedInto;
private final Set<CollapsedDependencyGraphComponent> unmodifiableOutgoing = Collections.unmodifiableSet(outgoingEdges);
private final Set<CollapsedDependencyGraphComponent> unmodifiableIncoming = Collections.unmodifiableSet(incomingEdges);
private CollapsedDependencyGraphComponent(int id) {
this.id = id;
this.hash = HashCommon.murmurHash3(id);
}
@Override
public int hashCode() {
return hash; // no need to enter native code to get a hashCode, that saves a few nanoseconds
}
private int y() {
if (!Main.STRICT_Y || positions.isEmpty()) {
throw new IllegalStateException();
}
if (y == -1) { // TODO won't work in 1.17+ lol
y = BetterBlockPos.YfromLong(positions.iterator().nextLong());
if (y == -1) {
throw new IllegalStateException();
}
}
return y;
}
public boolean deleted() {
return deletedInto != null;
}
public CollapsedDependencyGraphComponent deletedIntoRecursive() { // what cid was this merged into that caused it to be deleted
if (!deleted()) {
return this;
}
return deletedInto = deletedInto.deletedIntoRecursive();
}
public LongSet getPositions() {
if (deleted()) {
throw new IllegalStateException();
}
return LongSets.unmodifiable(positions);
}
public Set<CollapsedDependencyGraphComponent> getIncoming() {
if (deleted()) {
throw new IllegalStateException();
}
return unmodifiableIncoming;
}
public Set<CollapsedDependencyGraphComponent> getOutgoing() {
if (deleted()) {
throw new IllegalStateException();
}
return unmodifiableOutgoing;
}
@Override
public String toString() {
if (!Main.DEBUG) {
throw new IllegalStateException();
}
return "cid" + id;
}
}
private void sanityCheck() {
LongOpenHashSet inComponents = new LongOpenHashSet();
for (int componentID : components.keySet()) {
CollapsedDependencyGraphComponent component = components.get(componentID);
if (component.id != componentID) {
throw new IllegalStateException();
}
if (component.incomingEdges.contains(component) || component.outgoingEdges.contains(component)) {
throw new IllegalStateException(component.id + "");
}
if (component.positions.isEmpty()) {
throw new IllegalStateException();
}
Integer y = Main.STRICT_Y ? component.y() : null;
for (CollapsedDependencyGraphComponent out : component.outgoingEdges) {
if (Main.STRICT_Y && out.y() < y) {
throw new IllegalStateException();
}
if (!out.incomingEdges.contains(component)) {
throw new IllegalStateException();
}
if (component.incomingEdges.contains(out)) {
throw new IllegalStateException(out.id + " is both an incoming AND and outgoing of " + component.id);
}
}
for (CollapsedDependencyGraphComponent in : component.incomingEdges) {
if (Main.STRICT_Y && in.y() > y) {
throw new IllegalStateException();
}
if (!in.outgoingEdges.contains(component)) {
throw new IllegalStateException(in.id + " is an incoming edge of " + component.id + " but it doesn't have that as an outgoing edge");
}
if (component.outgoingEdges.contains(in)) {
throw new IllegalStateException();
}
}
LongIterator it = component.positions.iterator();
while (it.hasNext()) {
long l = it.nextLong();
if (posToComponent.get(l) != component) {
throw new IllegalStateException();
}
if (Main.STRICT_Y && BetterBlockPos.YfromLong(l) != y) {
throw new IllegalStateException();
}
if (!real(l)) {
throw new IllegalStateException();
}
}
inComponents.addAll(component.positions);
}
if (!inComponents.equals(posToComponent.keySet())) {
for (long l : posToComponent.keySet()) {
if (!inComponents.contains(l)) {
System.out.println(l);
System.out.println(posToComponent.get(l).id);
System.out.println(posToComponent.get(l).positions.contains(l));
System.out.println(posToComponent.get(l).deleted());
System.out.println(components.containsValue(posToComponent.get(l)));
throw new IllegalStateException(l + " is in posToComponent but not actually in any component");
}
}
throw new IllegalStateException("impossible");
}
}
}
private void checkEquality(CollapsedDependencyGraph a, CollapsedDependencyGraph b) {
if (a.components.size() != b.components.size()) {
throw new IllegalStateException(a.components.size() + " " + b.components.size());
}
if (a.posToComponent.size() != b.posToComponent.size()) {
throw new IllegalStateException();
}
if (!a.posToComponent.keySet().equals(b.posToComponent.keySet())) {
throw new IllegalStateException();
}
a.sanityCheck();
b.sanityCheck();
Int2IntOpenHashMap aToB = new Int2IntOpenHashMap();
for (int key : a.components.keySet()) {
aToB.put(key, b.posToComponent.get(a.components.get(key).positions.iterator().nextLong()).id);
}
for (int i : a.components.keySet()) {
int bInd = aToB.get(i);
if (!a.components.get(i).positions.equals(b.components.get(bInd).positions)) {
throw new IllegalStateException();
}
for (List<Set<CollapsedDependencyGraph.CollapsedDependencyGraphComponent>> toCompare : Arrays.asList(
Arrays.asList(a.components.get(i).incomingEdges, b.components.get(bInd).incomingEdges),
Arrays.asList(a.components.get(i).outgoingEdges, b.components.get(bInd).outgoingEdges)
)) {
Set<CollapsedDependencyGraph.CollapsedDependencyGraphComponent> aEdges = toCompare.get(0);
Set<CollapsedDependencyGraph.CollapsedDependencyGraphComponent> bEdges = toCompare.get(1);
if (aEdges.size() != bEdges.size()) {
throw new IllegalStateException();
}
for (CollapsedDependencyGraph.CollapsedDependencyGraphComponent dst : aEdges) {
if (!bEdges.contains(b.components.get(aToB.get(dst.id)))) {
throw new IllegalStateException();
}
}
}
}
}
}

View File

@@ -0,0 +1,138 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import baritone.builder.DependencyGraphScaffoldingOverlay.CollapsedDependencyGraph.CollapsedDependencyGraphComponent;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import it.unimi.dsi.fastutil.longs.LongIterator;
import it.unimi.dsi.fastutil.longs.LongList;
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
import java.util.Comparator;
import java.util.PriorityQueue;
import java.util.Set;
import java.util.stream.Collectors;
public enum DijkstraScaffolder implements IScaffolderStrategy {
INSTANCE;
@Override
public LongList scaffoldTo(CollapsedDependencyGraphComponent root, DependencyGraphScaffoldingOverlay overlayGraph) {
// TODO what if this root is unreachable, e.g. it's lower in STRICT_Y mode?
Set<CollapsedDependencyGraphComponent> exclusiveDescendents = new ObjectOpenHashSet<>();
walkAllDescendents(root, exclusiveDescendents);
exclusiveDescendents.remove(root);
PriorityQueue<ScaffoldingSearchNode> openSet = new PriorityQueue<>(Comparator.comparingInt(node -> node.costSoFar));
Long2ObjectOpenHashMap<ScaffoldingSearchNode> nodeMap = new Long2ObjectOpenHashMap<>();
LongIterator it = root.getPositions().iterator();
while (it.hasNext()) {
long l = it.nextLong();
nodeMap.put(l, new ScaffoldingSearchNode(l));
}
System.out.println(root.getPositions().stream().map(BetterBlockPos::fromLong).collect(Collectors.toList()));
openSet.addAll(nodeMap.values());
while (!openSet.isEmpty()) {
ScaffoldingSearchNode node = openSet.poll();
CollapsedDependencyGraphComponent tentativeComponent = overlayGraph.getCollapsedGraph().getComponentLocations().get(node.pos);
if (tentativeComponent != null) {
if (exclusiveDescendents.contains(tentativeComponent)) { // TODO is exclusiveDescendants even valid? returning a route into one of the descendants, if it's on the top of the heap, is valid because it closes a loop and the next dijkstra can start from there? perhaps there's no need to treat descendant interactions differently from any other non-root component? EDIT: maybe it's good to prevent adding useless scaffolding that closes loops for no good reason?
// have gone back onto a descendent of this node
// sadly this can happen even at the same Y level even in Y_STRICT mode due to orientable blocks forming a loop
continue; // TODO does this need to be here? can I expand THROUGH an unrelated component? probably requires testing, this is quite a mind bending possibility. cost should be zero i think?
} else {
// found a path to a component that isn't a descendent of the root
if (tentativeComponent != root) { // but if it IS the root, then we're just on our first loop iteration, we are far from done
return reconstructPathTo(node); // all done! found a path to a component unrelated to this one, meaning we have successfully connected this part of the build with scaffolding back to the rest of it
// TODO scaffolder strategy should be reworked into a coroutine-like format to decomposes a persistent dijkstra that retains the openset and nodemap between scaffolder component connections. each scaffoldersearchnode would need a persistent progeny (source component) and new combined components would need to be introduced as they're created. then the search can be simultaneous. this would solve the problem of potential incorrect selection of root node, as all possible root nodes are expanded at once
}
}
}
for (Face face : Face.VALUES) {
if (overlayGraph.hypotheticalScaffoldingIncomingEdge(node.pos, face)) { // we don't have to worry about an incoming edge going into the frontier set because the root component is strongly connected and has no incoming edges from other SCCs, therefore any and all incoming edges will come from hypothetical scaffolding air locations
long neighborPos = face.offset(node.pos);
int newCost = node.costSoFar + edgeCost(face); // TODO future edge cost should include an added modifier for if neighborPos is in a favorable or unfavorable position e.g. above / under a diagonal depending on if map art or not
ScaffoldingSearchNode existingNode = nodeMap.get(neighborPos);
if (existingNode != null) {
// it's okay if neighbor isn't marked as "air" in the overlay - that's what we want to find - a path to another component
// however, we can't consider neighbors within the same component as a solution, clearly
// we can accomplish this and kill two birds with one stone by skipping all nodes already in the node map
// any position in the initial frontier is clearly in the node map, but also any node that has already been considered
// this prevents useless cycling of equivalent paths
// this is okay because all paths are equivalent, so there is no possible way to find a better path (because currently it's a fixed value for horizontal / vertical movements)
if (existingNode.costSoFar > newCost) { // initialization nodes will have costSoFar = 0 as a base case
// note that obviously there is a loopback possibility: search one block north then one block south, you'll run into the same node again. that's fine - "costSoFar < newCost" doesn't mean anything
// same for diagonals: one block north then one block down, versus one block down then one block north. that's also fine - "costSoFar == newCost" doesn't mean anything
System.out.println(BetterBlockPos.fromLong(node.pos) + " to " + BetterBlockPos.fromLong(neighborPos) + " " + existingNode.costSoFar + " " + newCost + " " + root.getPositions().contains(node.pos) + " " + root.getPositions().contains(neighborPos) + " " + reconstructPathTo(node).stream().map(BetterBlockPos::fromLong).collect(Collectors.toList()) + " " + reconstructPathTo(existingNode).stream().map(BetterBlockPos::fromLong).collect(Collectors.toList()));
throw new IllegalStateException();
}
// TODO if root spans more than 1 y level, then this assumption is not correct because edgeCost is different for a horizontal vs vertical face, meaning that a neighbor can have different cost routes if both sideways and up are part of the root component
continue; // nothing to do - we already have an equal-or-better path to this location
}
ScaffoldingSearchNode newNode = new ScaffoldingSearchNode(neighborPos);
newNode.costSoFar = newCost;
newNode.prev = node;
nodeMap.put(newNode.pos, newNode);
openSet.add(newNode);
}
}
}
return null;
}
private static void walkAllDescendents(CollapsedDependencyGraphComponent root, Set<CollapsedDependencyGraphComponent> set) {
set.add(root);
for (CollapsedDependencyGraphComponent component : root.getOutgoing()) {
walkAllDescendents(component, set);
}
}
private static LongList reconstructPathTo(ScaffoldingSearchNode end) {
LongList path = new LongArrayList();
while (end != null) {
path.add(end.pos);
end = end.prev;
}
return path;
}
public static int edgeCost(Face face) {
if (Main.STRICT_Y && face == Face.UP) {
throw new IllegalStateException();
}
// gut feeling: give slight bias to moving horizontally
// that will influence it to create horizontal bridges more often than vertical pillars
// horizontal bridges are easier to maneuver around and over
if (face.y == 0) {
return 1;
}
return 2;
}
private static class ScaffoldingSearchNode {
private final long pos;
private int costSoFar;
private ScaffoldingSearchNode prev;
private ScaffoldingSearchNode(long pos) {
this.pos = pos;
}
}
}

View File

@@ -0,0 +1,940 @@
/*
* 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.builder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.stream.IntStream;
public class EulerTourForest {
static long parentWalks;
static long parentCalls;
// https://web.stanford.edu/class/archive/cs/cs166/cs166.1166/lectures/17/Small17.pdf
// https://u.cs.biu.ac.il/~rodittl/p723-holm.pdf
// https://web.archive.org/web/20180725100607/https://infoscience.epfl.ch/record/99353/files/HenzingerK99.pdf
// https://en.wikipedia.org/wiki/Dynamic_connectivity#The_Level_structure
public final BSTNode[] loopbacks; // a (v,v) fake edge is created per vertex and maintained at the appropriate location in the tree, to allow fast lookups of where "v" is, without having to rely on the presence or absence of tree edges connected to v
public EulerTourForest(int n) {
this.loopbacks = IntStream.range(0, n).mapToObj(SplayNode::new).toArray(BSTNode[]::new);
}
public TreeEdge link(int vertA, int vertB) {
if (connected(vertA, vertB)) {
throw new IllegalStateException();
}
BSTNode outgoing = new SplayNode(vertA, vertB);
BSTNode incoming = new SplayNode(vertB, vertA);
BSTNode.barrelRollToLowest(loopbacks[vertA]);
BSTNode.barrelRollToLowest(loopbacks[vertB]);
BSTNode.concatenate(loopbacks[vertA], outgoing); // (a,a) ... (a,b)
BSTNode.concatenate(outgoing, loopbacks[vertB]); // (a,a) ... (a,b) (b,b) ...
BSTNode.concatenate(loopbacks[vertB], incoming); // (a,a) ... (a,b) (b,b) ... (b,a)
return new TreeEdge(incoming, outgoing);
}
public void cut(TreeEdge edge) {
if (edge.owner() != this) {
throw new IllegalArgumentException();
}
if (edge.cut) {
return;
}
edge.cut = true;
BSTNode outgoing = edge.left;
BSTNode incoming = edge.right;
if (incoming.src != outgoing.dst || incoming.dst != outgoing.src || outgoing == incoming || incoming.src == incoming.dst) {
throw new IllegalStateException();
}
if (!connected(incoming.src, incoming.dst)) {
throw new IllegalStateException();
}
BSTNode.barrelRollToLowest(outgoing);
BSTNodePair disconnected = incoming.disconnect(Direction.RIGHT);
if (disconnected.left.walkDescendant(Direction.LEFT) != outgoing || disconnected.right.walkDescendant(Direction.LEFT) != incoming) {
throw new IllegalStateException();
}
if (loopbacks[incoming.src].walkAncestor() != disconnected.left || loopbacks[outgoing.src].walkAncestor() != disconnected.right) {
throw new IllegalStateException();
}
outgoing.remove();
incoming.remove();
}
public boolean connected(int vertA, int vertB) {
return loopbacks[vertA].walkAncestor() == loopbacks[vertB].walkAncestor();
}
public int size(int vert) {
return loopbacks[vert].walkAncestor().loopbackSize;
}
public int[] walk(int vert) {
BSTNode root = loopbacks[vert].walkAncestor();
int[] ret = new int[root.loopbackSize];
int[] idx = {0};
root.walk(node -> {
if (node.isLoopback()) {
ret[idx[0]++] = node.src;
}
});
return ret;
}
// redblacknode impl deleted here
public static class SplayNode extends BSTNode {
private SplayNode() {
super();
}
private SplayNode(int same) {
super(same);
}
private SplayNode(int src, int dst) {
super(src, dst);
}
public void splay() {
while (parent != null) {
BSTNode grandparent = parent.parent;
Direction myDir = whichChildAmI();
if (grandparent != null) {
Direction parentDir = parent.whichChildAmI();
if (myDir == parentDir) {
// see "Zig-zig step" of https://en.wikipedia.org/wiki/Splay_tree
grandparent.splayRotate(parentDir);
parent.splayRotate(myDir);
} else {
// see "Zig-zag step" of https://en.wikipedia.org/wiki/Splay_tree
parent.splayRotate(myDir);
grandparent.splayRotate(parentDir);
}
} else {
parent.splayRotate(myDir);
if (parent != null) {
throw new IllegalStateException();
}
}
}
}
@Override
protected BSTNode concatenateRoots(BSTNode right) {
if (this.parent != null || right.parent != null || this == right) {
throw new IllegalStateException();
}
SplayNode newRoot = (SplayNode) right.walkDescendant(Direction.LEFT);
newRoot.splay();
// newRoot is now the root of a splay tree containing all of right
// and, it is the LOWEST value of right, and left is assumed to be less than it, so now we can just attach left as its left child
// (since it is the lowest value of right, it cannot possibly have any left child already)
if (newRoot.getChild(Direction.LEFT) != null) {
throw new IllegalStateException();
}
newRoot.setChild(Direction.LEFT, this);
newRoot.childUpdated();
return newRoot;
}
@Override
protected BSTNodePair disconnect(Direction remainOnSide) {
splay(); // SIGNIFICANTLY easier to split the tree in half, if we are the root node
BSTNode left = this;
BSTNode right = this;
// simple detach of one side
if (remainOnSide == Direction.LEFT) {
right = rightChild;
rightChild = null;
childUpdated();
if (right != null) {
right.sizeMustBeAccurate();
right.parent = null;
}
} else {
left = leftChild;
leftChild = null;
childUpdated();
if (left != null) {
left.sizeMustBeAccurate();
left.parent = null;
}
}
return new BSTNodePair(left, right);
}
public void remove() {
splay();
if (leftChild != null) {
leftChild.parent = null;
}
if (rightChild != null) {
rightChild.parent = null;
}
if (leftChild != null && rightChild != null) {
leftChild.concatenateRoots(rightChild);
}
}
}
public abstract static class BSTNode {
protected final int src;
protected final int dst;
protected BSTNode leftChild;
protected BSTNode rightChild;
protected BSTNode parent;
protected int loopbackSize;
private BSTNode() {
this(-1);
}
private BSTNode(int same) {
this.src = same;
this.dst = same;
this.loopbackSize = 1;
}
private BSTNode(int src, int dst) {
if (src == dst) {
throw new IllegalArgumentException();
}
this.src = src;
this.dst = dst;
this.loopbackSize = 0;
}
protected void splayRotate(Direction dir) {
rotateSecret(dir);
}
protected void redBlackRotate(Direction dir) {
rotateSecret(dir.opposite()); // i guess they just use different conventions?
}
private void rotateSecret(Direction dir) {
// promote my "dir" child to my level, swap myself down to that level
// see "Zig step" of https://en.wikipedia.org/wiki/Splay_tree
BSTNode child = this.getChild(dir);
BSTNode replacementChild = child.getChild(dir.opposite()); // stays at the same level, is just rotated to the other side of the tree
this.setChild(dir, replacementChild);
if (parent == null) {
child.parent = null;
} else {
parent.setChild(whichChildAmI(), child);
}
child.setChild(dir.opposite(), this); // e.g. my left child now has me as their right child
childUpdated();
parent.childUpdated();
}
public static BSTNode concatenate(BSTNode left, BSTNode right) {
if (left == null) {
throw new IllegalStateException();
}
if (right == null) {
return left;
}
return left.walkAncestor().concatenateRoots(right.walkAncestor());
}
protected void afterSwap(BSTNode other) {
}
protected void swapLocationWith(BSTNode other) {
if (other == this) {
throw new IllegalStateException();
}
if (other.parent == this) {
other.swapLocationWith(this);
return;
}
if (parent == other) {
// grandpa
// other
// this otherChild
// left right
// and we want that to become
// grandpa
// this
// other otherChild
// left right
Direction dir = whichChildAmI(); // LEFT, in the above example
BSTNode otherChild = other.getChild(dir.opposite());
BSTNode left = leftChild;
BSTNode right = rightChild;
if (other.parent == null) { // grandpa
parent = null;
} else {
other.parent.setChild(other.whichChildAmI(), this);
}
setChild(dir, other);
setChild(dir.opposite(), otherChild);
other.setChild(Direction.LEFT, left);
other.setChild(Direction.RIGHT, right);
other.childUpdated();
childUpdated();
} else {
Direction myDir = parent == null ? null : whichChildAmI();
Direction otherDir = other.parent == null ? null : other.whichChildAmI();
BSTNode tmpLeft = leftChild;
BSTNode tmpRight = rightChild;
BSTNode tmpParent = parent;
if (other.parent == null) { // grandpa
parent = null;
} else {
other.parent.setChild(otherDir, this);
}
if (tmpParent == null) {
other.parent = null;
} else {
tmpParent.setChild(myDir, other);
}
setChild(Direction.LEFT, other.leftChild);
setChild(Direction.RIGHT, other.rightChild);
other.setChild(Direction.LEFT, tmpLeft);
other.setChild(Direction.RIGHT, tmpRight);
calcSize();
if (parent != null) {
parent.bubbleUpSize();
}
other.calcSize();
if (other.parent != null) {
other.parent.bubbleUpSize();
}
}
afterSwap(other);
}
protected abstract BSTNode concatenateRoots(BSTNode right);
public static BSTNode barrelRollToLowest(BSTNode target) {
// 1. chop the tree in half, centered at target
// 2. reattach them in the opposite order
// in other words, "cut the deck but don't riffle" - leave "target" as the first node (NOT necessarily the root node)
BSTNodePair pair = target.disconnect(Direction.RIGHT);
if ((target instanceof SplayNode && pair.right != target) || pair.right.parent != null) { // splay to root only happens with a splay tree, obviously
throw new IllegalStateException();
}
// target is now the lowest (leftmost) element of pair.right
BSTNode ret = BSTNode.concatenate(pair.right, pair.left); // target is now first, and everything else is still in order :D
// use concatenate and not concatenateRoots because pair.left could be null
if (ret == target && pair.left != null) {
throw new IllegalStateException();
}
return ret;
}
protected abstract BSTNodePair disconnect(Direction remainOnSide); // chops the tree in half, with "this" remaining on the side "remainOnSide"
public abstract void remove();
protected void bubbleUpSize() {
int ns = calcSize();
if (loopbackSize != ns) {
loopbackSize = ns;
if (parent != null) {
parent.bubbleUpSize();
}
}
}
protected void childUpdated() {
loopbackSize = calcSize();
}
protected void sizeMustBeAccurate() {
if (loopbackSize != calcSize()) {
throw new IllegalStateException();
}
}
protected int calcSize() {
int size = 0;
if (isLoopback()) {
size++;
}
if (rightChild != null) {
size += rightChild.loopbackSize;
}
if (leftChild != null) {
size += leftChild.loopbackSize;
}
return size;
}
protected BSTNode getChild(Direction dir) {
return dir == Direction.LEFT ? leftChild : rightChild;
}
protected void setChild(Direction dir, BSTNode newChild) {
if (newChild == this) {
throw new IllegalStateException();
}
if (dir == Direction.LEFT) {
leftChild = newChild;
} else {
rightChild = newChild;
}
if (newChild != null) {
newChild.parent = this;
}
}
protected Direction whichChildAmI() {
if (parent.leftChild == this) {
return Direction.LEFT;
}
if (parent.rightChild == this) {
return Direction.RIGHT;
}
throw new IllegalStateException();
}
protected BSTNode walkDescendant(Direction side) {
BSTNode child = getChild(side);
if (child == null) {
return this;
} else {
return child.walkDescendant(side);
}
}
protected BSTNode walkAncestor() {
BSTNode walk = this;
while (walk.parent != null) {
parentWalks++;
walk = walk.parent;
}
parentCalls++;
return walk;
/*if (parent == null) {
return this;
} else {
return parent.walkAncestor();
}*/
}
protected void walk(Consumer<BSTNode> consumer) {
if (leftChild != null) {
leftChild.walk(consumer);
}
consumer.accept(this);
if (rightChild != null) {
rightChild.walk(consumer);
}
}
protected BSTNode walkNext() {
if (rightChild != null) {
return rightChild.walkDescendant(Direction.LEFT);
}
BSTNode itr = this;
while (itr.parent != null && itr.whichChildAmI() == Direction.RIGHT) {
itr = itr.parent;
}
return itr.parent;
}
protected boolean isAlone() {
return parent == null && leftChild == null && rightChild == null;
}
public boolean isLoopback() {
return src == dst;
}
}
public enum Direction { // TODO check if proguard converts this to an int
LEFT, RIGHT;
public Direction opposite() {
return this == LEFT ? RIGHT : LEFT;
}
}
private static class BSTNodePair {
final BSTNode left;
final BSTNode right;
private BSTNodePair(BSTNode left, BSTNode right) {
this.left = left;
this.right = right;
if ((left != null && left.parent != null) || (right != null && right.parent != null)) {
throw new IllegalStateException();
}
}
}
public class TreeEdge {
private boolean cut;
final BSTNode left;
final BSTNode right;
private TreeEdge(BSTNode left, BSTNode right) {
this.left = left;
this.right = right;
}
private EulerTourForest owner() {
return EulerTourForest.this;
}
}
private static void mustEq(BSTNode a, BSTNode b) {
if (a != b) {
throw new IllegalStateException(a + " " + b);
}
}
public static void sanityCheck2() {
for (int i = 0; i < 9; i++) {
int mode = i % 3;
int SZ = 700;
TreeEdge[] up = new TreeEdge[SZ * SZ];
TreeEdge[] right = new TreeEdge[SZ * SZ];
EulerTourForest forest = new EulerTourForest(SZ * SZ);
for (int y = 0; y < SZ; y++) {
for (int x = 0; x < SZ; x++) {
if (y != SZ - 1) {
try {
up[x * SZ + y] = forest.link(x * SZ + y, x * SZ + (y + 1));
} catch (IllegalStateException ex) {} // ignore if already linked
}
if (x != SZ - 1) {
try {
right[x * SZ + y] = forest.link(x * SZ + y, (x + 1) * SZ + y);
} catch (IllegalStateException ex) {} // ignore if already linked
}
}
}
Random rand = new Random(5021);
for (int x = 0; x < SZ; x++) {
int y = SZ / 2;
forest.cut(up[x * SZ + y]);
//System.out.println("Sz " + forest.size(x * SZ + y));
}
if (mode == 1) {
for (int j = 0; j < SZ * SZ * 2; j++) { // *2 for a fair comparison to during connection, since that one splays both sides of each test
((EulerTourForest.SplayNode) forest.loopbacks[rand.nextInt(SZ * SZ)]).splay();
}
}
long a = System.currentTimeMillis();
parentCalls = 0; // reset metrics
parentWalks = 0;
for (int checks = 0; checks < SZ * SZ; checks++) {
int v1 = rand.nextInt(SZ * SZ);
int v2 = rand.nextInt(SZ * SZ);
forest.connected(v1, v2);
if (mode == 2) {
((SplayNode) forest.loopbacks[v1]).splay();
((SplayNode) forest.loopbacks[v2]).splay();
}
}
forest.checkForest(false);
if (mode == 0) {
System.out.println("WITHOUT random accesses");
} else if (mode == 1) {
System.out.println("WITH pre-connection random accesses");
} else {
System.out.println("WITH random accesses during connection");
}
System.out.println("Walk ancestor was called " + parentCalls + " times, and it traversed " + parentWalks + " in total, implying an average height of " + (parentWalks / (float) parentCalls));
System.out.println("Time: " + (System.currentTimeMillis() - a));
}
}
public static void sanityCheck() {
for (Direction dir : Direction.values()) {
System.out.println("Testing zig " + dir);
// see "Zig step" of https://en.wikipedia.org/wiki/Splay_tree
SplayNode p = new SplayNode();
SplayNode x = new SplayNode();
SplayNode A = new SplayNode();
SplayNode B = new SplayNode();
SplayNode C = new SplayNode();
p.setChild(dir, x);
p.setChild(dir.opposite(), C);
x.setChild(dir, A);
x.setChild(dir.opposite(), B);
x.splay();
mustEq(p.parent, x);
mustEq(p.getChild(dir), B);
mustEq(p.getChild(dir.opposite()), C);
mustEq(x.parent, null);
mustEq(x.getChild(dir), A);
mustEq(x.getChild(dir.opposite()), p);
mustEq(A.parent, x);
mustEq(A.getChild(dir), null);
mustEq(A.getChild(dir.opposite()), null);
mustEq(B.parent, p);
mustEq(B.getChild(dir), null);
mustEq(B.getChild(dir.opposite()), null);
mustEq(C.parent, p);
mustEq(C.getChild(dir), null);
mustEq(C.getChild(dir.opposite()), null);
}
for (Direction dir : Direction.values()) {
System.out.println("Testing zig-zig " + dir);
// see "Zig-zig step" of https://en.wikipedia.org/wiki/Splay_tree
SplayNode g = new SplayNode();
SplayNode p = new SplayNode();
SplayNode x = new SplayNode();
SplayNode A = new SplayNode();
SplayNode B = new SplayNode();
SplayNode C = new SplayNode();
SplayNode D = new SplayNode();
g.setChild(dir, p);
g.setChild(dir.opposite(), D);
p.setChild(dir, x);
p.setChild(dir.opposite(), C);
x.setChild(dir, A);
x.setChild(dir.opposite(), B);
x.splay();
mustEq(g.parent, p);
mustEq(g.getChild(dir), C);
mustEq(g.getChild(dir.opposite()), D);
mustEq(p.parent, x);
mustEq(p.getChild(dir), B);
mustEq(p.getChild(dir.opposite()), g);
mustEq(x.parent, null);
mustEq(x.getChild(dir), A);
mustEq(x.getChild(dir.opposite()), p);
mustEq(A.parent, x);
mustEq(A.getChild(dir), null);
mustEq(A.getChild(dir.opposite()), null);
mustEq(B.parent, p);
mustEq(B.getChild(dir), null);
mustEq(B.getChild(dir.opposite()), null);
mustEq(C.parent, g);
mustEq(C.getChild(dir), null);
mustEq(C.getChild(dir.opposite()), null);
mustEq(D.parent, g);
mustEq(D.getChild(dir), null);
mustEq(D.getChild(dir.opposite()), null);
}
for (Direction dir : Direction.values()) {
System.out.println("Testing zig-zag " + dir);
// see "Zig-zag step" of https://en.wikipedia.org/wiki/Splay_tree
SplayNode g = new SplayNode();
SplayNode p = new SplayNode();
SplayNode x = new SplayNode();
SplayNode A = new SplayNode();
SplayNode B = new SplayNode();
SplayNode C = new SplayNode();
SplayNode D = new SplayNode();
g.setChild(dir, p);
g.setChild(dir.opposite(), D);
p.setChild(dir, A);
p.setChild(dir.opposite(), x);
x.setChild(dir, B);
x.setChild(dir.opposite(), C);
x.splay();
mustEq(g.parent, x);
mustEq(g.getChild(dir), C);
mustEq(g.getChild(dir.opposite()), D);
mustEq(p.parent, x);
mustEq(p.getChild(dir), A);
mustEq(p.getChild(dir.opposite()), B);
mustEq(x.parent, null);
mustEq(x.getChild(dir), p);
mustEq(x.getChild(dir.opposite()), g);
mustEq(A.parent, p);
mustEq(A.getChild(dir), null);
mustEq(A.getChild(dir.opposite()), null);
mustEq(B.parent, p);
mustEq(B.getChild(dir), null);
mustEq(B.getChild(dir.opposite()), null);
mustEq(C.parent, g);
mustEq(C.getChild(dir), null);
mustEq(C.getChild(dir.opposite()), null);
mustEq(D.parent, g);
mustEq(D.getChild(dir), null);
mustEq(D.getChild(dir.opposite()), null);
}
for (Direction GtoP : Direction.values()) {
for (Direction PtoX : Direction.values()) {
System.out.println("Testing connected swap " + GtoP + " " + PtoX);
SplayNode g = new SplayNode();
SplayNode p = new SplayNode();
SplayNode x = new SplayNode();
SplayNode A = new SplayNode();
SplayNode B = new SplayNode();
SplayNode C = new SplayNode();
SplayNode D = new SplayNode();
g.setChild(GtoP, p);
g.setChild(GtoP.opposite(), D);
p.setChild(PtoX, x);
p.setChild(PtoX.opposite(), A);
x.setChild(Direction.LEFT, B);
x.setChild(Direction.RIGHT, C);
/*x.black = true;
p.black = false;*/
p.swapLocationWith(x);
/*if (x.black || !p.black) {
throw new IllegalStateException();
}*/
mustEq(g.parent, null);
mustEq(g.getChild(GtoP), x);
mustEq(g.getChild(GtoP.opposite()), D);
mustEq(p.parent, x);
mustEq(p.getChild(Direction.LEFT), B);
mustEq(p.getChild(Direction.RIGHT), C);
mustEq(x.parent, g);
mustEq(x.getChild(PtoX), p);
mustEq(x.getChild(PtoX.opposite()), A);
mustEq(A.parent, x);
mustEq(A.getChild(Direction.LEFT), null);
mustEq(A.getChild(Direction.RIGHT), null);
mustEq(B.parent, p);
mustEq(B.getChild(Direction.LEFT), null);
mustEq(B.getChild(Direction.RIGHT), null);
mustEq(C.parent, p);
mustEq(C.getChild(Direction.LEFT), null);
mustEq(C.getChild(Direction.RIGHT), null);
mustEq(D.parent, g);
mustEq(D.getChild(Direction.LEFT), null);
mustEq(D.getChild(Direction.RIGHT), null);
}
}
for (Direction APtoA : Direction.values()) {
for (Direction BPtoB : Direction.values()) {
System.out.println("Testing disconnected swap " + APtoA + " " + BPtoB);
SplayNode ap = new SplayNode();
SplayNode apoc = new SplayNode();
SplayNode a = new SplayNode();
SplayNode alc = new SplayNode();
SplayNode arc = new SplayNode();
SplayNode bp = new SplayNode();
SplayNode bpoc = new SplayNode();
SplayNode b = new SplayNode();
SplayNode blc = new SplayNode();
SplayNode brc = new SplayNode();
ap.setChild(APtoA, a);
ap.setChild(APtoA.opposite(), apoc);
a.setChild(Direction.LEFT, alc);
a.setChild(Direction.RIGHT, arc);
bp.setChild(BPtoB, b);
bp.setChild(BPtoB.opposite(), bpoc);
b.setChild(Direction.LEFT, blc);
b.setChild(Direction.RIGHT, brc);
/*a.black = true;
b.black = false;*/
a.swapLocationWith(b);
/*if (a.black || !b.black) {
throw new IllegalStateException();
}*/
mustEq(ap.parent, null);
mustEq(ap.getChild(APtoA), b);
mustEq(ap.getChild(APtoA.opposite()), apoc);
mustEq(apoc.parent, ap);
mustEq(apoc.getChild(Direction.LEFT), null);
mustEq(apoc.getChild(Direction.RIGHT), null);
mustEq(a.parent, bp);
mustEq(a.getChild(Direction.LEFT), blc);
mustEq(a.getChild(Direction.RIGHT), brc);
mustEq(alc.parent, b);
mustEq(alc.getChild(Direction.LEFT), null);
mustEq(alc.getChild(Direction.RIGHT), null);
mustEq(arc.parent, b);
mustEq(arc.getChild(Direction.LEFT), null);
mustEq(arc.getChild(Direction.RIGHT), null);
mustEq(bp.parent, null);
mustEq(bp.getChild(BPtoB), a);
mustEq(bp.getChild(BPtoB.opposite()), bpoc);
mustEq(bpoc.parent, bp);
mustEq(bpoc.getChild(Direction.LEFT), null);
mustEq(bpoc.getChild(Direction.RIGHT), null);
mustEq(b.parent, ap);
mustEq(b.getChild(Direction.LEFT), alc);
mustEq(b.getChild(Direction.RIGHT), arc);
mustEq(blc.parent, a);
mustEq(blc.getChild(Direction.LEFT), null);
mustEq(blc.getChild(Direction.RIGHT), null);
mustEq(brc.parent, a);
mustEq(brc.getChild(Direction.LEFT), null);
mustEq(brc.getChild(Direction.RIGHT), null);
}
}
{
Random rand = new Random(5021);
List<Supplier<BSTNode>> constructors = Arrays.asList(SplayNode::new/*, SplayNode::new*/);
for (int run = 0; run < 10; run++) {
int NODES = 10000;
Supplier<BSTNode> toUse = constructors.get(run % constructors.size());
List<BSTNode> nodes = new ArrayList<>();
{
BSTNode root = toUse.get();
nodes.add(root);
for (int i = 1; i < NODES; i++) {
nodes.add(toUse.get());
root = BSTNode.concatenate(root, nodes.get(i));
}
}
int shuffledBy = 0;
for (int ii = 0; ii < 10000; ii++) {
if (rand.nextBoolean()) {
BSTNode root = nodes.get(rand.nextInt(NODES));
if (root instanceof SplayNode) {
((SplayNode) root).splay();
if (root != nodes.get(rand.nextInt(NODES)).walkAncestor() || root.loopbackSize != NODES) {
throw new IllegalStateException();
}
} else {
throw new IllegalStateException();
}
}
if (rand.nextBoolean()) {
shuffledBy = rand.nextInt(NODES);
BSTNode root = BSTNode.barrelRollToLowest(nodes.get(shuffledBy));
if (root != nodes.get(rand.nextInt(NODES)).walkAncestor() || root.loopbackSize != NODES) {
throw new IllegalStateException();
}
}
if (rand.nextBoolean()) {
int pos = rand.nextBoolean() ? (shuffledBy + NODES + rand.nextInt(10) - 5) % NODES : rand.nextInt(NODES);
BSTNode remove = nodes.remove(pos);
NODES--;
remove.remove();
if (shuffledBy > pos) {
shuffledBy--;
}
}
List<BSTNode> order = new ArrayList<>(NODES);
nodes.get(rand.nextInt(NODES)).walkAncestor().walk(order::add);
for (int n = 0; n < NODES; n++) {
if (order.get(n) != nodes.get((n + shuffledBy) % NODES)) {
throw new IllegalStateException();
}
order.get(n).sizeMustBeAccurate();
if (order.get(n).walkNext() != (n < NODES - 1 ? order.get(n + 1) : null)) {
throw new IllegalStateException();
}
}
}
}
}
{
// slide 22 of https://web.stanford.edu/class/archive/cs/cs166/cs166.1166/lectures/17/Small17.pdf
EulerTourForest forest = new EulerTourForest(11);
forest.link(0, 1);
forest.link(1, 3);
forest.link(2, 4);
forest.link(1, 2);
TreeEdge toCut = forest.link(0, 5);
forest.link(5, 6);
forest.link(6, 9);
forest.link(9, 10);
forest.link(9, 8);
forest.link(6, 7);
BSTNode.barrelRollToLowest(forest.loopbacks[0]);
if (!forest.checkForest(true).equals("abdbcecbafgjkjijghgf")) {
throw new IllegalStateException();
}
forest.cut(toCut);
if (!forest.checkForest(true).equals("abdbcecb fgjkjijghg")) {
throw new IllegalStateException();
}
}
{
// slide 26 of https://web.stanford.edu/class/archive/cs/cs166/cs166.1166/lectures/17/Small17.pdf
EulerTourForest forest = new EulerTourForest(11);
forest.link(2, 4);
TreeEdge toCut = forest.link(2, 1);
forest.link(1, 0);
forest.link(1, 3);
forest.link(2, 6);
forest.link(6, 9);
forest.link(9, 10);
forest.link(9, 8);
forest.link(6, 7);
forest.link(5, 6);
BSTNode.barrelRollToLowest(forest.loopbacks[2]);
if (!forest.checkForest(true).equals("cecbabdbcgjkjijghgfg")) {
throw new IllegalStateException();
}
forest.cut(toCut);
if (!forest.checkForest(true).equals("babd cgjkjijghgfgce")) {
throw new IllegalStateException();
}
}
}
public String checkForest(boolean verbose) {
boolean[] seen = new boolean[loopbacks.length];
StringBuilder ret = new StringBuilder();
for (int vert = 0; vert < loopbacks.length; vert++) {
if (seen[vert]) {
continue;
}
List<BSTNode> order = new ArrayList<>();
loopbacks[vert].walkAncestor().walk(order::add);
for (int i = 0; i < order.size(); i++) {
if (verbose) {
System.out.print("(" + (char) ('a' + order.get(i).src) + "," + (char) ('a' + order.get(i).dst) + ") ");
}
if (order.get(i).dst != order.get((i + 1) % order.size()).src) {
throw new IllegalStateException();
}
if (order.get(i).isLoopback()) {
seen[order.get(i).src] = true;
} else {
ret.append((char) ('a' + order.get(i).src));
}
}
if (verbose) {
System.out.println();
}
ret.append(" ");
if (!seen[vert]) {
throw new IllegalStateException();
}
}
if (verbose) {
System.out.println(ret);
}
return ret.toString().trim();
}
}

View File

@@ -0,0 +1,94 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import net.minecraft.util.EnumFacing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
/**
* I hate porting things to new versions of Minecraft
* <p>
* So just like BetterBlockPos, we now have Face
*/
public enum Face {
DOWN, UP, NORTH, SOUTH, WEST, EAST;
public final int index = ordinal();
public final int oppositeIndex = opposite(index);
public final int x = toMC().getXOffset();
public final int y = toMC().getYOffset();
public final int z = toMC().getZOffset();
public final long offset = BetterBlockPos.toLong(x, y, z); // both the previous three lines (avoidably) and this one (unavoidably due to BlockPos superclass of BetterBlockPos) mess up test timing / profiling because it calls the <clinit> of both EnumFacing and BlockPos which does some Log4j bs lol
public final int[] vec = new int[]{x, y, z};
public final boolean vertical = y != 0;
public final int horizontalIndex = x & 1 | (x | z) & 2;
public static final int NUM_FACES = 6;
public static final Face[] VALUES = new Face[NUM_FACES];
public static final Face[] HORIZONTALS = new Face[4];
public static final List<Optional<Face>> OPTS;
public static final long[] OFFSETS = new long[NUM_FACES];
static {
List<Optional<Face>> lst = new ArrayList<>();
for (Face face : values()) {
VALUES[face.index] = face;
OFFSETS[face.index] = face.offset;
lst.add(Optional.of(face));
HORIZONTALS[face.horizontalIndex] = face;
}
lst.add(Optional.empty());
OPTS = Collections.unmodifiableList(lst);
}
public final EnumFacing toMC() {
return EnumFacing.byIndex(index);
}
public final Face opposite() {
return VALUES[oppositeIndex];
}
public final long offset(long pos) {
return (pos + offset) & BetterBlockPos.POST_ADDITION_MASK;
}
public static long offset(long pos, int face) {
return (pos + OFFSETS[face]) & BetterBlockPos.POST_ADDITION_MASK;
}
public static int opposite(int face) {
return face ^ 1;
}
public static int oppositeHorizontal(int horizontalIndex) {
return horizontalIndex ^ 2;
}
public static Face between(long from, long to) {
for (int i = 0; i < NUM_FACES; i++) {
if (offset(from, i) == to) {
return VALUES[i];
}
}
return null;
}
}

View File

@@ -0,0 +1,88 @@
/*
* 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.builder;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
/**
* There will be a BlockStateCachedData for every IBlockState in the game, yes.
* <p>
* But, we need some additional BlockStateCachedDatas. For example, we need one that represents hypothetical scaffolding, and another for air, for properly computing place order dependency graphs. Some other places need a placeholder for out of bounds.
* <p>
* We could just say that scaffolding is always, like, dirt, or something. But that would be inelegant.
* <p>
* And beyond the needs at runtime, unit tests shouldn't need to bootstrap and boot up the entire Minecraft game. So, let's have some fake BlockStateCachedData for testing purposes too!
*/
public class FakeStates {
// the three aformentioned placeholders for runtime
public static final BlockStateCachedData SCAFFOLDING = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).fullyWalkableTop().collisionHeight(1).canPlaceAgainstMe());
// need a second solid block so that "== FakeStates.SCAFFOLDING" doesn't get tricked
public static final BlockStateCachedData SOLID = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).fullyWalkableTop().collisionHeight(1).canPlaceAgainstMe());
public static final BlockStateCachedData AIR = new BlockStateCachedData(new BlockStateCachedDataBuilder().setAir());
public static final BlockStateCachedData OUT_OF_BOUNDS = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).collisionHeight(1));
// and some for testing
public static final BlockStateCachedData[] BY_HEIGHT;
static {
BY_HEIGHT = new BlockStateCachedData[Blip.FULL_BLOCK + 1];
for (int height = 1; height <= Blip.FULL_BLOCK; height++) {
BY_HEIGHT[height] = new BlockStateCachedData(new BlockStateCachedDataBuilder().collidesWithPlayer(true).fullyWalkableTop().collisionHeight(height * Blip.RATIO));
}
BY_HEIGHT[0] = AIR;
}
private static List<BlockStateCachedData> PROBABLE_BLOCKS = null;
private static List<BlockStateCachedData> getProbableBlocks() {
if (PROBABLE_BLOCKS == null) {
//long a = System.currentTimeMillis();
Random rand = new Random(5021);
PROBABLE_BLOCKS = IntStream.range(0, 10000).mapToObj($ -> {
List<BlockStatePlacementOption> ret = new ArrayList<>(SCAFFOLDING.placeMe);
ret.removeIf($$ -> rand.nextInt(10) < 2);
BlockStateCachedDataBuilder builder = new BlockStateCachedDataBuilder() {
@Override
public List<BlockStatePlacementOption> howCanIBePlaced() {
return ret;
}
};
if (ret.isEmpty()) {
builder.placementLogicNotImplementedYet();
}
return new BlockStateCachedData(builder
.fullyWalkableTop()
.collisionHeight(1)
.canPlaceAgainstMe()
.collidesWithPlayer(true));
}).collect(Collectors.toList());
//System.out.println("Took " + (System.currentTimeMillis() - a));
}
return PROBABLE_BLOCKS;
}
public static BlockStateCachedData probablyCanBePlaced(Random rand) {
return getProbableBlocks().get(rand.nextInt(getProbableBlocks().size()));
}
// probably more will go here such as for making sure that slabs and stairs work right (like there'll be a fake slab and a fake stair i guess?)
}

View File

@@ -0,0 +1,298 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import java.util.ArrayDeque;
import java.util.ArrayList;
public class GreedySolver {
private final SolverEngineInput engineInput;
private final NodeBinaryHeap heap = new NodeBinaryHeap();
private final Long2ObjectOpenHashMap<Node> nodes = new Long2ObjectOpenHashMap<>();
private final ZobristWorldStateCache zobristCache;
private final long allCompleted;
private final Bounds bounds;
private Column scratchpadExpandNode1 = new Column();
private Column scratchpadExpandNode2 = new Column();
private Column scratchpadExpandNode3 = new Column();
public GreedySolver(SolverEngineInput input) {
this.engineInput = input;
this.bounds = engineInput.graph.bounds();
this.zobristCache = new ZobristWorldStateCache(new WorldState.WorldStateWrappedSubstrate(engineInput));
Node root = new Node(engineInput.player, null, 0L, -1L, 0);
nodes.put(root.nodeMapKey(), root);
heap.insert(root);
this.allCompleted = WorldState.predetermineGoalZobrist(engineInput.allToPlaceNow);
}
synchronized SolverEngineOutput search() {
while (!heap.isEmpty()) {
Node node = heap.removeLowest();
if (!node.sneaking() && node.worldStateZobristHash == allCompleted) {
return backwards(node);
}
expandNode(node);
}
throw new UnsupportedOperationException();
}
private SolverEngineOutput backwards(Node node) {
ArrayDeque<SolvedActionStep> steps = new ArrayDeque<>();
while (node.previous != null) {
steps.addFirst(step(node, node.previous));
node = node.previous;
}
return new SolverEngineOutput(new ArrayList<>(steps));
}
private SolvedActionStep step(Node next, Node prev) {
if (next.worldStateZobristHash == prev.worldStateZobristHash) {
return new SolvedActionStep(next.pos());
} else {
return new SolvedActionStep(next.pos(), WorldState.unzobrist(prev.worldStateZobristHash ^ next.worldStateZobristHash));
}
}
private boolean wantToPlaceAt(long blockGoesAt, Node vantage, int blipsWithinVoxel, WorldState worldState) {
if (worldState.blockExists(blockGoesAt)) {
return false;
}
long vpos = vantage.pos();
int relativeX = BetterBlockPos.XfromLong(vpos) - BetterBlockPos.XfromLong(blockGoesAt);
int relativeY = blipsWithinVoxel + Blip.FULL_BLOCK * (BetterBlockPos.YfromLong(vpos) - BetterBlockPos.YfromLong(blockGoesAt));
int relativeZ = BetterBlockPos.ZfromLong(vpos) - BetterBlockPos.ZfromLong(blockGoesAt);
BlockStateCachedData blockBeingPlaced = engineInput.graph.data(blockGoesAt);
for (BlockStatePlacementOption option : blockBeingPlaced.placeMe) {
long maybePlaceAgainst = option.against.offset(blockGoesAt);
if (!bounds.inRangePos(maybePlaceAgainst)) {
continue;
}
if (!worldState.blockExists(maybePlaceAgainst)) {
continue;
}
BlockStateCachedData placingAgainst = engineInput.graph.data(maybePlaceAgainst);
PlaceAgainstData againstData = placingAgainst.againstMe(option);
traces:
for (Raytracer.Raytrace trace : option.computeTraceOptions(againstData, relativeX, relativeY, relativeZ, PlayerVantage.LOOSE_CENTER, blockReachDistance())) { // TODO or only take the best one
for (long l : trace.passedThrough) {
if (worldState.blockExists(l)) {
continue traces;
}
}
return true;
}
}
return false;
}
private void expandNode(Node node) {
WorldState worldState = zobristCache.coalesceState(node);
long pos = node.pos();
Column within = scratchpadExpandNode1;
within.initFrom(pos, worldState, engineInput);
Column supportedBy;
boolean sneaking = node.sneaking();
if (sneaking) {
supportedBy = scratchpadExpandNode3;
long supportedFeetVoxel = SneakPosition.sneakDirectionFromPlayerToSupportingBlock(node.sneakingPosition()).offset(pos);
supportedBy.initFrom(supportedFeetVoxel, worldState, engineInput);
if (Main.DEBUG && !within.okToSneakIntoHereAtHeight(supportedBy.feetBlips)) {
throw new IllegalStateException();
}
} else {
supportedBy = within;
}
int playerFeet = supportedBy.feetBlips;
if (Main.DEBUG && !supportedBy.playerCanExistAtFootBlip(playerFeet)) {
throw new IllegalStateException();
}
// -------------------------------------------------------------------------------------------------------------
// place block beneath or within feet voxel
for (int dy = -1; dy <= 0; dy++) {
// this is the common case for sneak bridging with full blocks
long maybePlaceAt = BetterBlockPos.offsetBy(pos, 0, dy, 0);
BlockStateCachedData wouldBePlaced = engineInput.graph.data(maybePlaceAt);
int cost = blockPlaceCost();
int playerFeetWouldBeAt = playerFeet;
/*if (wouldBePlaced.collidesWithPlayer) {
int heightRelativeToCurrentVoxel = wouldBePlaced.collisionHeightBlips() + dy * Blip.FULL_BLOCK;
if (heightRelativeToCurrentVoxel > playerFeet) {
// we would need to jump in order to do this
cost += jumpCost();
playerFeetWouldBeAt = heightRelativeToCurrentVoxel; // because we'd have to jump, and could only place the block once we had cleared the collision box for it
if (!within.playerCanExistAtFootBlip(heightRelativeToCurrentVoxel) || !supportedBy.playerCanExistAtFootBlip(heightRelativeToCurrentVoxel)) {
continue;
}
}
}
if (wantToPlaceAt(maybePlaceAt, node, playerFeetWouldBeAt, worldState)) {
upsertEdge(node, worldState, pos, null, maybePlaceAt, cost);
}*/
}
// -------------------------------------------------------------------------------------------------------------
if (sneaking) {
// we can walk back to where we were
upsertEdge(node, worldState, supportedBy.pos, null, -1, flatCost());
// this will probably rarely be used. i can only imagine rare scenarios such as needing the extra perspective in order to place a block a bit more efficiently. like, this could avoid unnecessary ancillary scaffolding i suppose.
// ----
// also let's try just letting ourselves fall off the edge of the block
int descendBy = PlayerPhysics.playerFalls(pos, worldState, engineInput);
if (descendBy != -1) {
upsertEdge(node, worldState, BetterBlockPos.offsetBy(pos, 0, -descendBy, 0), null, -1, fallCost(descendBy));
}
return;
}
// not sneaking! sneaking returned ^^
// -------------------------------------------------------------------------------------------------------------
// walk sideways and either stay level, ascend, or descend
Column into = scratchpadExpandNode2;
for (Face travel : Face.HORIZONTALS) {
long newPos = travel.offset(pos);
into.initFrom(newPos, worldState, engineInput);
PlayerPhysics.Collision collision = PlayerPhysics.playerTravelCollides(within, into);
switch (collision) {
case BLOCKED: {
continue;
}
case FALL: {
upsertEdge(node, worldState, newPos, travel, -1, flatCost()); // sneak off edge of block
break;
}
default: {
long realNewPos = BetterBlockPos.offsetBy(newPos, 0, collision.voxelVerticalOffset(), 0);
upsertEdge(node, worldState, realNewPos, null, -1, collision.requiresJump() ? jumpCost() : flatCost());
break;
}
}
}
}
private int fallCost(int blocks) {
if (blocks < 1) {
throw new IllegalStateException();
}
throw new UnsupportedOperationException();
}
private int flatCost() {
throw new UnsupportedOperationException();
}
private int jumpCost() {
throw new UnsupportedOperationException();
}
private double blockReachDistance() {
throw new UnsupportedOperationException();
}
private void upsertEdge(Node node, WorldState worldState, long newPlayerPosition, Face sneakingTowards, long blockPlacement, int edgeCost) {
Node neighbor = getNode(newPlayerPosition, sneakingTowards, node, worldState, blockPlacement);
if (Main.SLOW_DEBUG && blockPlacement != -1 && !zobristCache.coalesceState(neighbor).blockExists(blockPlacement)) { // only in slow_debug because this force-allocates a WorldState for every neighbor of every node!
throw new IllegalStateException();
}
if (Main.DEBUG && node == neighbor) {
throw new IllegalStateException();
}
updateNeighbor(node, neighbor, edgeCost);
}
private void updateNeighbor(Node node, Node neighbor, int edgeCost) {
int currentCost = neighbor.cost;
int offeredCost = node.cost + edgeCost;
if (currentCost < offeredCost) {
return;
}
neighbor.previous = node;
neighbor.cost = offeredCost;
neighbor.combinedCost = offeredCost + neighbor.heuristic;
if (Main.DEBUG && neighbor.combinedCost < Integer.MIN_VALUE / 2) { // simple attempt to catch obvious overflow
throw new IllegalStateException();
}
if (neighbor.inHeap()) {
heap.update(neighbor);
} else {
heap.insert(neighbor);
}
}
private int calculateHeuristicModifier(WorldState previous, long blockPlacedAt) {
if (Main.DEBUG && previous.blockExists(blockPlacedAt)) {
throw new IllegalStateException();
}
if (true) {
throw new UnsupportedOperationException("tune the values first lol");
}
switch (engineInput.desiredToBePlaced(blockPlacedAt)) {
case PART_OF_CURRENT_GOAL:
case SCAFFOLDING_OF_CURRENT_GOAL:
return -100; // keep kitten on task
case PART_OF_FUTURE_GOAL:
return -10; // smaller kitten treat for working ahead
case SCAFFOLDING_OF_FUTURE_GOAL:
return -5; // smallest kitten treat for working ahead on scaffolding
case ANCILLARY:
return 0; // no kitten treat for placing a random extra block
default:
throw new IllegalStateException();
}
}
private int blockPlaceCost() {
// maybe like... ten?
throw new UnsupportedOperationException();
}
private Node getNode(long playerPosition, Face sneakingTowards, Node prev, WorldState prevWorld, long blockPlacement) {
if (Main.DEBUG && blockPlacement != -1 && prevWorld.blockExists(blockPlacement)) {
throw new IllegalStateException();
}
long worldStateZobristHash = prev.worldStateZobristHash;
if (blockPlacement != -1) {
worldStateZobristHash = WorldState.updateZobrist(worldStateZobristHash, blockPlacement);
}
long code = SneakPosition.encode(playerPosition, sneakingTowards) ^ worldStateZobristHash;
Node existing = nodes.get(code);
if (existing != null) {
return existing;
}
int newHeuristic = prev.heuristic;
if (blockPlacement != -1) {
newHeuristic += calculateHeuristicModifier(prevWorld, blockPlacement);
}
Node node = new Node(playerPosition, null, worldStateZobristHash, blockPlacement, newHeuristic);
if (Main.DEBUG && node.nodeMapKey() != code) {
throw new IllegalStateException();
}
nodes.put(code, node);
return node;
}
public BlockStateCachedData at(long pos, WorldState inWorldState) {
return engineInput.at(pos, inWorldState);
}
}

View File

@@ -0,0 +1,27 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
public enum GreedySolverEngine implements ISolverEngine {
INSTANCE;
@Override
public SolverEngineOutput solve(SolverEngineInput in) {
return new GreedySolver(in).search();
}
}

View File

@@ -0,0 +1,22 @@
/*
* 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.builder;
public enum Half {
TOP, BOTTOM, EITHER
}

View File

@@ -0,0 +1,44 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
public interface IBlockStateDataProvider {
int numStates();
BlockStateCachedData getNullable(int i);
default BlockStateCachedData[] allNullable() {
BlockStateCachedData[] ret = new BlockStateCachedData[numStates()];
RuntimeException ex = null;
for (int i = 0; i < ret.length; i++) {
try {
ret[i] = getNullable(i);
} catch (RuntimeException e) {
if (ex != null) {
ex.printStackTrace(); // printstacktrace all but the one that we throw
}
ex = e;
}
}
if (ex != null) {
throw ex; // throw the last one
}
return ret;
}
}

View File

@@ -0,0 +1,21 @@
/*
* 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.builder;
public interface INavigableSurface {
}

View File

@@ -0,0 +1,33 @@
/*
* 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.builder;
import it.unimi.dsi.fastutil.longs.LongList;
public interface IReachabilityProvider {
LongList candidates(long playerEyeVoxel);
static IReachabilityProvider get(DependencyGraphScaffoldingOverlay overlay, PlayerReachSphere sphere) {
try {
return new ReachabilityCache(overlay, sphere);
} catch (ReachabilityCache.SchematicIsTooDenseForThisToMakeSenseException ex) {
return new ReachabilityLive(overlay, sphere);
}
}
}

View File

@@ -0,0 +1,27 @@
/*
* This file is part of Baritone.
*
* Baritone is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Baritone is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Baritone. If not, see <https://www.gnu.org/licenses/>.
*/
package baritone.builder;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.LongList;
public interface IScaffolderStrategy {
// TODO passing in DGSO is not ideal because it's mutable
// TODO should it instead take in a list of (all) possible roots?
LongList scaffoldTo(DependencyGraphScaffoldingOverlay.CollapsedDependencyGraph.CollapsedDependencyGraphComponent root, DependencyGraphScaffoldingOverlay overlayGraph);
}

View File

@@ -0,0 +1,23 @@
/*
* 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.builder;
public interface ISolverEngine {
SolverEngineOutput solve(SolverEngineInput in);
}

View File

@@ -0,0 +1,346 @@
/*
* 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.builder;
import baritone.api.pathing.movement.ActionCosts;
import baritone.api.utils.BetterBlockPos;
import baritone.builder.mc.DebugStates;
import baritone.builder.mc.VanillaBlockStateDataProvider;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import java.util.Random;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
public class Main {
public static final boolean DEBUG = true;
public static final boolean SLOW_DEBUG = false;
public static final boolean VERY_SLOW_DEBUG = false;
/**
* If true, many different parts of the builder switch to a more efficient mode where blocks can only be placed adjacent or upwards, never downwards
*/
public static final boolean STRICT_Y = true;
public static final BlockData DATA = new BlockData(new VanillaBlockStateDataProvider());
public static final Random RAND = new Random(5021);
public static void main() throws InterruptedException {
System.out.println("Those costs are " + (ActionCosts.FALL_N_BLOCKS_COST[2] / 2) + " and " + ActionCosts.JUMP_ONE_BLOCK_COST + " and " + ActionCosts.FALL_N_BLOCKS_COST[1]);
for (Face face : Face.VALUES) {
System.out.println(face);
System.out.println(face.x);
System.out.println(face.y);
System.out.println(face.z);
System.out.println(face.index);
System.out.println(face.offset);
System.out.println(face.oppositeIndex);
System.out.println("Horizontal " + face.horizontalIndex);
}
{
System.out.println("Without");
long start = BetterBlockPos.toLong(5021, 69, 420);
System.out.println(BetterBlockPos.fromLong(start));
start += Face.UP.offset;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.DOWN.offset;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.UP.offset;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.DOWN.offset;
System.out.println(BetterBlockPos.fromLong(start));
}
{
System.out.println("With");
long start = BetterBlockPos.toLong(5021, 69, 420);
System.out.println(BetterBlockPos.fromLong(start));
start += Face.UP.offset;
start &= BetterBlockPos.POST_ADDITION_MASK;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.DOWN.offset;
start &= BetterBlockPos.POST_ADDITION_MASK;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.UP.offset;
start &= BetterBlockPos.POST_ADDITION_MASK;
System.out.println(BetterBlockPos.fromLong(start));
start += Face.DOWN.offset;
start &= BetterBlockPos.POST_ADDITION_MASK;
System.out.println(BetterBlockPos.fromLong(start));
}
{
System.out.println(BetterBlockPos.fromLong(BetterBlockPos.toLong(150, 150, 150)));
}
for (int i = 0; i < 0; i++) {
Stream.of(new Object())
.flatMap(ignored -> IntStream.range(0, 100).boxed())
.parallel()
.forEach(x -> System.out.println(x + ""));
IntStream.range(100, 200).boxed()
.parallel()
.forEach(x -> System.out.println(x + ""));
Stream.of(new Object())
.flatMap(ignored -> IntStream.range(200, 300).boxed())
.collect(Collectors.toList()).parallelStream()
.forEach(x -> System.out.println(x + ""));
}
for (int aaaa = 0; aaaa < 0; aaaa++) {
/*Raytracer.raytraceMode++;
Raytracer.raytraceMode %= 3;*/
Random rand = new Random(5021);
DoubleArrayList A = new DoubleArrayList();
DoubleArrayList B = new DoubleArrayList();
DoubleArrayList C = new DoubleArrayList();
DoubleArrayList D = new DoubleArrayList();
DoubleArrayList E = new DoubleArrayList();
DoubleArrayList F = new DoubleArrayList();
LongArrayList G = new LongArrayList();
long a = System.currentTimeMillis();
for (int trial = 0; trial < 10_000_000; ) {
Vec3d playerEye = new Vec3d(rand.nextDouble() * 5 - 2.5, rand.nextDouble() * 5, rand.nextDouble() * 5 - 2.5);
long eyeBlock = playerEye.getRoundedToZeroPositionUnsafeDontUse();
if (eyeBlock == 0) {
// origin, unlucky
continue;
}
Face placeToAgainst = Face.VALUES[rand.nextInt(Face.NUM_FACES)];
Face againstToPlace = placeToAgainst.opposite();
long placeAgainst = placeToAgainst.offset(0);
if (eyeBlock == placeAgainst) {
continue;
}
double[] hitVec = new double[3];
for (int i = 0; i < 3; i++) {
switch (placeToAgainst.vec[i]) {
case -1: {
hitVec[i] = 0;
break;
}
case 0: {
hitVec[i] = rand.nextDouble();
break;
}
case 1: {
hitVec[i] = 1;
break;
}
}
}
Vec3d hit = new Vec3d(hitVec);
Raytracer.runTrace(playerEye, placeAgainst, againstToPlace, hit);
A.add(playerEye.x);
B.add(playerEye.y);
C.add(playerEye.z);
D.add(hit.x);
E.add(hit.y);
F.add(hit.z);
G.add(placeAgainst);
trial++;
}
long b = System.currentTimeMillis();
System.out.println("Nominal first run with overhead: " + (b - a) + "ms");
boolean checkAgainst = true;
for (int i = 0; i < 10_000_000; i++) {
if (i % 1000 == 0 && checkAgainst) {
System.out.println(i);
}
LongArrayList normal = Raytracer.rayTraceZoomy(A.getDouble(i), B.getDouble(i), C.getDouble(i), D.getDouble(i), E.getDouble(i), F.getDouble(i), G.getLong(i));
LongArrayList alternate = Raytracer.rayTraceZoomyAlternate(A.getDouble(i), B.getDouble(i), C.getDouble(i), D.getDouble(i), E.getDouble(i), F.getDouble(i), G.getLong(i));
if (!normal.equals(alternate)) {
throw new IllegalStateException();
}
if (checkAgainst) {
LongArrayList superSlow = Raytracer.rayTraceFast(A.getDouble(i), B.getDouble(i), C.getDouble(i), D.getDouble(i), E.getDouble(i), F.getDouble(i));
if (!normal.equals(superSlow)) {
Raytracer.print(normal);
Raytracer.print(superSlow);
checkAgainst = false;
}
}
}
for (int it = 0; it < 20; it++) {
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
Raytracer.rayTraceZoomy(A.getDouble(i), B.getDouble(i), C.getDouble(i), D.getDouble(i), E.getDouble(i), F.getDouble(i), G.getLong(i));
}
long end = System.currentTimeMillis();
System.out.println("Normal took " + (end - start) + "ms");
}
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < 10_000_000; i++) {
Raytracer.rayTraceZoomyAlternate(A.getDouble(i), B.getDouble(i), C.getDouble(i), D.getDouble(i), E.getDouble(i), F.getDouble(i), G.getLong(i));
}
long end = System.currentTimeMillis();
System.out.println("Alternate took " + (end - start) + "ms");
}
}
}
{
DebugStates.debug();
}
for (int aaaa = 0; aaaa < 0; aaaa++) {
Random rand = new Random(5021);
int trials = 10_000_000;
int[] X = new int[trials];
int[] Y = new int[trials];
int[] Z = new int[trials];
int sz = 10;
CuboidBounds bounds = new CuboidBounds(sz, sz, sz);
for (int i = 0; i < trials; i++) {
for (int[] toAdd : new int[][]{X, Y, Z}) {
toAdd[i] = rand.nextBoolean() ? rand.nextInt(sz) : rand.nextBoolean() ? -1 : sz;
}
}
boolean[] a = new boolean[trials];
boolean[] b = new boolean[trials];
boolean[] c = new boolean[trials];
boolean[] d = new boolean[trials];
boolean[] e = new boolean[trials];
for (int it = 0; it < 20; it++) {
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < trials; i++) {
a[i] = bounds.inRangeBranchy(X[i], Y[i], Z[i]);
}
long end = System.currentTimeMillis();
System.out.println("Branchy took " + (end - start) + "ms");
}
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < trials; i++) {
b[i] = bounds.inRangeBranchless(X[i], Y[i], Z[i]);
}
long end = System.currentTimeMillis();
System.out.println("Branchless took " + (end - start) + "ms");
}
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < trials; i++) {
c[i] = bounds.inRangeBranchless2(X[i], Y[i], Z[i]);
}
long end = System.currentTimeMillis();
System.out.println("Branchless2 took " + (end - start) + "ms");
}
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < trials; i++) {
d[i] = bounds.inRangeBranchless3(X[i], Y[i], Z[i]);
}
long end = System.currentTimeMillis();
System.out.println("Branchless3 took " + (end - start) + "ms");
}
{
Thread.sleep(1000);
System.gc();
Thread.sleep(1000);
long start = System.currentTimeMillis();
for (int i = 0; i < trials; i++) {
e[i] = bounds.inRangeBranchless4(X[i], Y[i], Z[i]);
}
long end = System.currentTimeMillis();
System.out.println("Branchless4 took " + (end - start) + "ms");
}
/*
Branchless2 took 55ms
Branchless3 took 53ms
Branchless4 took 47ms
Branchy took 137ms
Branchless took 35ms
Branchless2 took 36ms
Branchless3 took 35ms
Branchless4 took 41ms
Branchy took 118ms
Branchless took 33ms
Branchless2 took 39ms
Branchless3 took 36ms
Branchless4 took 42ms
Branchy took 125ms
Branchless took 41ms
Branchless2 took 45ms
Branchless3 took 41ms
Branchless4 took 45ms
Branchy took 123ms
Branchless took 38ms
Branchless2 took 43ms
Branchless3 took 35ms
Branchless4 took 43ms
Branchy took 117ms
Branchless took 37ms
Branchless2 took 42ms
Branchless3 took 41ms
Branchless4 took 45ms
Branchy took 123ms
Branchless took 35ms
Branchless2 took 42ms
Branchless3 took 38ms
Branchless4 took 46ms
Branchy took 126ms
Branchless took 34ms
Branchless2 took 47ms
Branchless3 took 40ms
Branchless4 took 47ms
Branchy took 124ms
*/
// 3 is better than 2 and 4 because of data dependency
// the L1 cache fetch for this.sizeX can happen at the same time as "x+1" (which is an increment of an argument)
// in other words: in options 2 and 4, the "+1" or "-1" has a data dependency on the RAM fetch for this.sizeX, but in option 3 alone, the +1 happens upon the argument x, which is likely in a register, meaning it can be pipelined in parallel with the L1 cache fetch for this.sizeX
}
}
/*{ // proguard test
PlayerPhysics.determinePlayerRealSupport(BlockStateCachedData.get(69), BlockStateCachedData.get(420));
PlayerPhysics.determinePlayerRealSupport(BlockStateCachedData.get(420), BlockStateCachedData.get(69));
}*/
{
for (int sneak = 0; sneak < 4; sneak++) {
System.out.println("meow");
System.out.println(sneak);
System.out.println(SneakPosition.encode(0, sneak));
System.out.println(SneakPosition.encode(BetterBlockPos.POST_ADDITION_MASK, sneak));
System.out.println(SneakPosition.decode(SneakPosition.encode(0, sneak)));
System.out.println(SneakPosition.decode(SneakPosition.encode(BetterBlockPos.POST_ADDITION_MASK, sneak)));
}
}
System.exit(0);
}
}

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.builder;
import baritone.api.utils.BetterBlockPos;
import baritone.builder.utils.com.github.btrekkie.connectivity.Augmentation;
import baritone.builder.utils.com.github.btrekkie.connectivity.ConnGraph;
import java.util.Arrays;
import java.util.function.Function;
public class NavigableSurface {
private final CuboidBounds bounds;
private final BlockStateCachedData[] blocks; // TODO switch to xzy ordering so columnFrom is faster
private final ConnGraph connGraph;
private final Function<BetterBlockPos, Object> genVertexAugmentation;
private final Column col1 = new Column();
private final Column col2 = new Column();
public NavigableSurface(int x, int y, int z, Augmentation augmentation, Function<BetterBlockPos, Object> genVertexAugmentation) {
this.bounds = new CuboidBounds(x, y, z);
this.blocks = new BlockStateCachedData[bounds.volume()];
Arrays.fill(blocks, FakeStates.AIR);
this.genVertexAugmentation = genVertexAugmentation;
this.connGraph = new ConnGraph(augmentation);
if (!genVertexAugmentation.apply(new BetterBlockPos(0, 0, 0)).equals(genVertexAugmentation.apply(new BetterBlockPos(0, 0, 0)))) {
throw new IllegalStateException("RedBlackNode optimization requires correct impl of .equals on the attachment, to avoid percolating up spurious augmentation non-updates");
}
}
private void columnFrom(Column column, long pos) {
column.underneath = getBlockOrAir((pos + Column.DOWN_1) & BetterBlockPos.POST_ADDITION_MASK);
column.feet = getBlockOrAir(pos);
column.head = getBlockOrAir((pos + Column.UP_1) & BetterBlockPos.POST_ADDITION_MASK);
column.above = getBlockOrAir((pos + Column.UP_2) & BetterBlockPos.POST_ADDITION_MASK);
column.aboveAbove = getBlockOrAir((pos + Column.UP_3) & BetterBlockPos.POST_ADDITION_MASK);
column.init();
}
protected void setBlock(long pos, BlockStateCachedData data) {
blocks[bounds.toIndex(pos)] = data;
for (int dy = -2; dy <= 1; dy++) {
long couldHaveChanged = BetterBlockPos.offsetBy(pos, 0, dy, 0);
columnFrom(col1, couldHaveChanged);
boolean currentlyAllowed = col1.standing();
if (currentlyAllowed) {
// TODO skip the next line if it already has an augmentation?
connGraph.setVertexAugmentation(couldHaveChanged, genVertexAugmentation.apply(BetterBlockPos.fromLong(couldHaveChanged)));
for (Face dir : Face.HORIZONTALS) {
long adj = dir.offset(couldHaveChanged);
columnFrom(col2, adj);
Integer connDy = PlayerPhysics.bidirectionalPlayerTravel(col1, col2, getBlockOrAir((adj + Column.DOWN_2) & BetterBlockPos.POST_ADDITION_MASK), getBlockOrAir((adj + Column.DOWN_3) & BetterBlockPos.POST_ADDITION_MASK));
for (int fakeDy = -2; fakeDy <= 2; fakeDy++) {
long neighbor = BetterBlockPos.offsetBy(adj, 0, fakeDy, 0);
if (((Integer) fakeDy).equals(connDy)) {
connGraph.addEdge(couldHaveChanged, neighbor);
} else {
connGraph.removeEdge(couldHaveChanged, neighbor);
}
}
}
} else {
connGraph.removeVertexAugmentation(couldHaveChanged);
for (Face dir : Face.HORIZONTALS) {
long adj = dir.offset(couldHaveChanged);
for (int fakeDy = -2; fakeDy <= 2; fakeDy++) {
connGraph.removeEdge(couldHaveChanged, BetterBlockPos.offsetBy(adj, 0, fakeDy, 0));
}
}
}
}
}
protected void setBlock(int x, int y, int z, BlockStateCachedData data) {
setBlock(BetterBlockPos.toLong(x, y, z), data);
}
public CuboidBounds bounds() {
return bounds;
}
public BlockStateCachedData getBlock(long pos) {
return blocks[bounds.toIndex(pos)];
}
public BlockStateCachedData getBlockOrAir(long pos) {
if (!bounds.inRangePos(pos)) {
return FakeStates.AIR;
}
return getBlock(pos);
}
public boolean hasBlock(BetterBlockPos pos) {
return getBlockOrAir(pos.toLong()).collidesWithPlayer;
}
public boolean connected(BetterBlockPos a, BetterBlockPos b) {
return connGraph.connected(a.toLong(), b.toLong());
}
public Object getComponentAugmentation(BetterBlockPos pos) { // maybe should be protected? subclass defines it anyway
return connGraph.getComponentAugmentation(pos.toLong());
}
}

View File

@@ -0,0 +1,66 @@
/*
* 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.builder;
import baritone.api.utils.BetterBlockPos;
public class Node {
private final long posAndSneak;
public final long worldStateZobristHash;
public final int heuristic;
public int cost;
public int combinedCost;
public Node previous;
int heapPosition;
// boolean unrealizedZobristBlockChange; // no longer needed since presence in the overall GreedySolver zobristWorldStateCache indicates if this is a yet-unrealized branch of the zobrist space
long packedUnrealizedCoordinate;
// int unrealizedState; // no longer needed now that world state is binarized with scaffolding/build versus air
// long unrealizedZobristParentHash; // no longer needed since we can compute it backwards with XOR
public Node(long pos, Face sneakingTowards, long zobristState, long unrealizedBlockPlacement, int heuristic) {
this.posAndSneak = SneakPosition.encode(pos, sneakingTowards);
this.heapPosition = -1;
this.cost = Integer.MAX_VALUE;
this.heuristic = heuristic;
this.worldStateZobristHash = zobristState;
this.packedUnrealizedCoordinate = unrealizedBlockPlacement;
}
public boolean sneaking() {
return SneakPosition.hasSneak(posAndSneak);
}
public long pos() {
return posAndSneak & BetterBlockPos.POST_ADDITION_MASK;
}
public long sneakingPosition() {
return posAndSneak;
}
public long nodeMapKey() {
return posAndSneak ^ worldStateZobristHash;
}
public boolean inHeap() {
return heapPosition >= 0;
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.builder;
import java.util.Arrays;
public class NodeBinaryHeap {
private static final int INITIAL_CAPACITY = 1024;
private Node[] array;
private int size;
public NodeBinaryHeap() {
this.size = INITIAL_CAPACITY;
this.array = new Node[this.size];
}
public int size() {
return size;
}
public void insert(Node value) {
if (size >= array.length - 1) {
array = Arrays.copyOf(array, array.length << 1);
}
size++;
value.heapPosition = size;
array[size] = value;
update(value);
}
public void update(Node val) {
int index = val.heapPosition;
int parentInd = index >>> 1;
int cost = val.combinedCost;
Node parentNode = array[parentInd];
while (index > 1 && parentNode.combinedCost > cost) {
array[index] = parentNode;
array[parentInd] = val;
val.heapPosition = parentInd;
parentNode.heapPosition = index;
index = parentInd;
parentInd = index >>> 1;
parentNode = array[parentInd];
}
}
public boolean isEmpty() {
return size == 0;
}
public Node removeLowest() {
if (size == 0) {
throw new IllegalStateException();
}
Node result = array[1];
Node val = array[size];
array[1] = val;
val.heapPosition = 1;
array[size] = null;
size--;
result.heapPosition = -1;
if (size < 2) {
return result;
}
int index = 1;
int smallerChild = 2;
int cost = val.combinedCost;
do {
Node smallerChildNode = array[smallerChild];
int smallerChildCost = smallerChildNode.combinedCost;
if (smallerChild < size) {
Node rightChildNode = array[smallerChild + 1];
int rightChildCost = rightChildNode.combinedCost;
if (smallerChildCost > rightChildCost) {
smallerChild++;
smallerChildCost = rightChildCost;
smallerChildNode = rightChildNode;
}
}
if (cost <= smallerChildCost) {
break;
}
array[index] = smallerChildNode;
array[smallerChild] = val;
val.heapPosition = smallerChild;
smallerChildNode.heapPosition = index;
index = smallerChild;
} while ((smallerChild <<= 1) <= size);
return result;
}
}

Some files were not shown because too many files have changed in this diff Show More