diff --git a/src/main/java/baritone/builder/README.md b/src/main/java/baritone/builder/README.md index 8cf69d389..61038a740 100644 --- a/src/main/java/baritone/builder/README.md +++ b/src/main/java/baritone/builder/README.md @@ -4,14 +4,14 @@ I will write more documentation eventually, I have some planning documents that The current Baritone BuilderProcess has a number of issues, no one disagrees there. The question is whether to try and fix those issues, or to start from scratch. I believe that starting from scratch is a good idea in this case. The reason is that I want to change the fundamental approach to building schematics. The current approach is basically "do whatever places / breaks I can from wherever I happen to be at the moment" and also "and if I can't work on anything from here, pathfind to a coordinate where I probably will be able to". This suffers from an inherently unfixable problem, which is that **there is no plan**. There are an untold number of infinite loops it can get stuck in that I have just hack patched over. Did you know that whenever the builder places a block, it increments a counter so that for the next five ticks (0.25 seconds) it won't consider breaking any blocks? This was my fix for it just placing and breaking the same block over and over. Did you know that the builder only places blocks at or below foot level purely because otherwise it would stupidly box itself in, because it isn't thinking ahead to "if I cover myself in blocks, I won't be able to walk to the next thing I need to do". And this doesn't even get into the larger scale infinite loops. I patched over the short ones, where it gets itself stuck within seconds, but the long term ones are a different beast. For example, the pathfinder that takes it to the next task can place / break blocks to get there. It has strict penalties for undoing work in the schematic, of course, but sometimes that's the only way forward. And in that scenario, it can cause infinite loops where each cycle lasts 30+ seconds ("nothing to do here, let's pathfind to the other side of the schematic" -> break a block in order to get there -> arrive at the other end -> "whoa i need to go place that block" -> walk back to where it started and place that block -> repeat the cycle). -So the idea, as you might have guessed from that foreshadowing, is that the new builder will generate a **complete** plan that includes interspersed actions of placing blocks and moving the player. This plan will be coherent and will not suffer from the issues of the current pathfinder in which costs are unable to take into account the previous actions that have changed the world. I'll say more on that later. This does mean that the schematic builder will not use the same path planner as the rest of Baritone. It may use the same **executor** though: why not. Nothing wrong with `new MovementTraverse(src, dest).update()`. +So the idea, as you might have guessed from that foreshadowing, is that the new builder will generate a **complete** plan that includes interspersed actions of placing blocks and moving the player. This plan will be coherent and will not suffer from the issues of the current pathfinder in which costs are unable to take into account the previous actions that have changed the world. I'll say more on that later. This does mean that the schematic builder will not use the same path planner as the rest of Baritone. Current restrictions that the builder will have, at least initially: * No breaking blocks. If you want to `cleararea` you can just use the old one, it works fine for that specific thing, at least. * For that reason, the schematic area should be clear. Think of this like a 3d printer going from bottom to top. It takes in a schematic, generates a plan of how to build it, and executes it. * Because it generates a full plan, if you think about it, this means that your schematic needs to be plannable. Therefore, if your schematic has something unplaceable in it, it won't even begin to do anything. I'll probably add an option to just skip impossible blocks with a warning. But plan for certain things (e.g. lava) to not be possible. -I want to make this package less dependent on Minecraft code. Perhaps this will be fully strict (put all Minecraft imports into a subpackage), perhaps it will just be best-effort. The idea is that I hate having to change all the stupid mapping names and deal with merge conflicts on those. For that reason I plan to use `int` instead of `IBlockState` everywhere, and basically do like `cachedData[state].isAir` instead of `state.getBlock() instanceof BlockAir` (so like `cachedData` would be a `BlockStateCachedData[]` with one entry per valid `IBlockState`). Then, for different versions of the game, all that would need to change is the code to populate array. This should help with checks like can-walk-on and can-place-against. +This is less dependent on Minecraft code. I'm too annoyed by things like `IBlockState` -> `BlockState` or `player.motionY()` -> `player.getMotion().y` or `== Blocks.AIR` -> `instanceof BlockAir`. For now, I've put everything that imports from Minecraft code into a subpackage called `mc`. I will probably stick with that. Basically I hate having to change all the stupid mapping names and deal with merge conflicts on those. For that reason I plan to use `int` instead of `IBlockState` everywhere, and basically do like `cachedData[state].isAir` instead of `state.getBlock() instanceof BlockAir` (so like `cachedData` would be a `BlockStateCachedData[]` with one entry per valid `IBlockState`). Then, for different versions of the game, all that would need to change is the code to populate array. This should help with checks like can-walk-on and can-place-against. If all the blocks that existed in Minecraft were solid, can-walk-on, can-place-against, this would be trivially easy. (I know - even for schematics of blocks like that, the current builder has problems.) Even for blocks such as glazed terracotta that have orientation, it would be okay. @@ -22,3 +22,5 @@ The current pathfinder makes a naive assumption that every movement's starting p I don't want to go too much further into how a traditional graph search algorithm could work here, as I'm not even certain that's what would work best. I'm considering STAN (an offshoot of graphplan) as well. It might be a hybrid solution, who knows. (e.g. try naive DFS, if that can't find a plan after X milliseconds, then fall back to graphplan). I'm not sure how to think about performance for this. Obviously there are copes like "pregenerate a plan for a schematic, reuse it". There are also copes like "just throw it in another thread, who cares how long it takes". Because if I dump in a 128x128x128 schematic of all stone (two million blocks), it takes a few seconds to separate the strongly connected components. Is that okay? I think it is. Lol. + +One particularly annoying thing is needing to reimplement portions of Minecraft. For example, there is a bit of code that I can easily call that says "If I looked in this direction right now, and right clicked, what block precisely would it place". Because, well, Minecraft needs to decide what block appears if and when I right click. This works great for current Baritone and I can just call it without needing to worry. For this builder though, I need to do hypotheticals. "If I were standing here on top of this block (that doesn't exist yet), looking at this face of this block (which doesn't exist yet), and right clicked while holding this item (which I don't have), what block would appear?". Minecraft code isn't built like that. There are so many conditions based on Y hit, face hit, player orientation, etc. Just look at the trapdoor place logic to instantly die. So I need to reimplement all the code for "I desire this block state (northward facing upside down acacia stairs). How can I make this coordinate contain that block? (well, you need to be facing north and right click the top face of an adjacent block with such a stair)". That code needs to be written for every block that has custom placement like that. The question of "If block X is at coordinate Y, could I right click against that to place block Z on face D" is incredibly frustratingly not easily answerable. It all depends on external variables like the horizontal orientation of the player, and even the Y coordinate of the player (for some blocks like pistons and dispensers). \ No newline at end of file