-
Notifications
You must be signed in to change notification settings - Fork 170
1: Documentation: Big Picture
Probably best to briefly skim this through before designing any tasks.
AltoClef is a Minecraft Bot system that can accomplish tasks.
To help accomplish these tasks, a bunch of utilities are included to make your life easier.
Imagine you want to go to the store and get some milk. Let's start by specifying a series of specific instructions that will accomplish this.
- Take the bus to the store
- Enter the store
- Find the milk
- Buy the milk
- Go home with the milk
Now suppose these instructions are handed to a contrarian who will follow these instructions to a tee, no matter what. This contrarian will never skip instructions and will keep the same order. Now suppose the contrarian finds themself inside the store already, and you tell them to "buy you some milk". In order to "buy milk", the contrarian will get on a bus to the store, probably the same store they started in. Without skipping a step, the contrarian will waste time and money.
So let's imagine instead that we add some conditions to when each step should occur.
-
Did we pay for milk and have milk in our hands?
- Yes: Go to: home
-
No: Are we in the store?
-
Yes: Did we pay for the milk?
- Yes: Grab the milk we paid for
- No: Find some milk and buy it
- No: Go to: the store
-
Yes: Did we pay for the milk?
Now, instead of a series of instructions we have a dichotomous tree/"20 questions game" that can tell a person what to do at any given time.
You'll notice we're missing a few details, like using the bus. Thankfully, we can add this in using abstraction
-
Are we riding a bus?
-
Yes: Is the bus stopped at the closest bus-stop to
X
?- Yes: Get off the bus
- No: Keep riding the bus
-
No: Are we within walking distance to
X
?-
Yes: Walk to
X
- No: Board the nearest bus
-
Yes: Walk to
-
Yes: Is the bus stopped at the closest bus-stop to
Now that "Go To X
" is defined, it becomes a reusable task that can be used to go to almost any place (assuming it's reachable by a bus).
There is actually a problem with this task, which is "What happens if the closest bus stop to X
is NOT within walking distance?". Detecting these kinds of problems ahead of time is quite tricky, but with some practice you'll get the hang of it.
Now let's move on to an example in Minecraft.
For a brief video explanation, Check this explanation, starting at 6:27.
Each item icon is a resource, and the "tree branches" extending downward are connected to SUB resources needed to get the resource higher in the tree. If one of these SUB resources is already obtained, the bot will ignore that part of the tree and move on to un-obtained SUB resources. If all SUB resources are obtained, they are combined to obtain the parent resource. The order of which SUB resource is picked is arbitrary/can be ignored. With this in place, the bot will not repeat tasks and will SKIP collecting resources already in its inventory.
This tree idea can be improved just a bit though, since we can see a lot of repetition here. An example of this repetition is found in planks, sticks, and the crafting table which repeat multiple times. If you’re a programmer, you probably know where this is going.
(Some diagram explanations: On the left side of the cobblestone is a wooden pick, indicating that a wood pickaxe is needed before mining the stone. For each pickaxe, a crafting table represents the need for a crafting table placed down somewhere nearby.)
This diagram represents the same tree as above but with a few improvements. Firstly, resources only need to be defined once and they can then be re-used. This re-use is akin to creating functions in a computer program, which is an easy way to avoid repeating work.
Thanks to this efficiency, we can extend this task to collect diamonds. Here’s what a diamond collection tree looks like:
(Here we also have a small furnace icon near the iron ingot resource, indicating that iron ore needs to be smelted in a nearby furnace to get the ingot)
Notice that we only needed to add three trees here to get to diamonds. However, if we stuck with the “full tree” approach we would need to create a massive single tree.
If we want to get diamonds, the above tree would work on Peaceful difficulty but fail everywhere else. This failure would be caused by hostile mobs and the environment killing the bot repeatedly.
To avoid this failure, the bot has multiple "task trees" running at once (hereby dubbed "task chains"), executing the task given by the the "task chain" with the highest priority. By default, the highest priority goes to the User task chain, that runs whatever command you feed into AltoClef (ex. @get diamond
). However, whenever a hostile mob gets too close or the bot gets hungry, the "Mob Defense Chain" and "Food Chain" increase in priority, and thus kick in.
With this system the bot can juggle survival and getting stuff done. Not the best solution, but it works.
It's important to remember that bots are pretty stupid. Like computers, they will do exactly what you TELL them to do, not what you WANT them to do.
Let's say we want to program a bot to build a bridge. Let's plan out how this may look like:
if the bot doesn't have building materials:
Collect cobblestone
else:
for each part of the bridge:
if it's not built yet:
Place a block of cobblestone there.
Each part of the bridge has been built, we're done!
Try to think about where the bot may fail if it tries running this. What can go wrong?
Here's one answer: The bot will get stuck repeatedly breaking and rebuilding the bridge. While building, if you tell the bot to Collect cobblestone
, nothing stops it from simply breaking apart the bridge it just built to get these materials.
And even if the bot has infinite building materials, baritone's pathfinding can get stuck breaking the bridge to walk past it, only to rebuild it immediately afterwards.
In this situation, there's a utility system that can receive a Predicate that tells Baritone to NOT mine/break a block. There are many other systems like this in AltoClef that help fix these kinds of issues.
But the point here is to be diligent when designing tasks. Scrutinize your tasks while writing them to see what may go wrong, and I'm sure you'll find something.
Overall, most issues boil down to one of two things:
- Baritone breaks/places a block somewhere where it shouldn't. Use
AltoClef.getBehaviour().avoidBlockBreaking(blockPos -> protect?)
- Whenever the bot is told to ALWAYS go to the closest target, it's very likely the bot may get stuck alternating between two target. In that case, either commit to a target whenever you find one, or use
DoToClosestBlockTask
/DoToClosestEntityTask
- The block you're traveling to may be unreachable (surrounded in bedrock, floating in the air and you don't have build materials). In that case use
AltoClef.getBlockTracker().unreachable(blockpos)
On the other end, even if you fix the problem you also gotta consider if your fix is too restrictive. Particularly with preventing Baritone from mining or placing. The bot may get stuck because it can't dig itself out of a room or pillar or whatever, so try to only restrict breaking/placing if you need to.
Not every single one of these issues can be solved or even discovered, but a good 99.9% of them can be found by testing your task a few times and trying to break the bot (give it less/more items, put it in specific situations that might break it, etc.)