As I worked on the concept of a Feature, I also came up with the idea of a FeatureCursor to make drawing in a Feature a little easier to do. A cursor is a lot like what you are probably thinking. It’s a system for tracking a position within a Feature. You can move it around and place blocks as you go. There are also fun bulk block placement methods for drawing lines and quickly putting up walls and that sort of thing.
At first, I imagined this cursor thing would only be useful in a Feature, but then I got to thinking a similar thing would be useful for drawing in the world directly too. Then another one for filling in the blocks in a raw chunk came to mind. That means these cursor things became something useful for all sorts of generators when constructing the world.
There are several different concepts of geography space in QubeKwest. The world itself operates in 3-tier geography space (blocks in chunks in clusters), Features operate in 2-tier geography space (blocks in chunks), and raw Chunks operate in 1-tier geography space (just the blocks they contain). What that means is that the trickiest parts of getting cursors to work are making sure they move in the appropriate number of tiers correctly, that they follow the bounds of the space they are working in, and of course that placing blocks follows the correct rules. That meant a little bit of refactoring was in order.
I didn’t want to have to rewrite the various line drawing and wall placing functions for each new type of cursor that I ended up making, which meant the creation of a new parent class called BlockCursor. It is abstract and holds all the bulk placement methods so child cursors only need to provide how the cursor moves around and how blocks are placed for all of the same drawing methods to work across multiple cursors.
For that to work however, I had to make sure none of the methods in BlockCursor ever tried to directly set the position of the cursor (because it can’t know what geography space is being used) or to draw anything using methods other than the ones provided by child cursors. When I found a C++ implementation of Bresenham’s line algorithm in 3D it became especially important that I didn’t have to maintain multiple versions of that method after I’d rewritten it in Java and made it work with cursors. It’s a pretty hairy algorithm it get right and maintaining multiple versions of it for different cursors would be a terrible idea.
After a bit of work, I am satisfied that my pattern for cursors is sound. Whether that remains true mostly depends on whether or not actually using these cursors in the various generators proves to be a pain. That is a bridge I will cross some other time so I can remain focused on actual progress.