ave / blockworld

In case you were wondering why I haven't updated this site or finished the Lisp page for a whole week, you might be a bit obsessed with checking my website (weirdo (aff.)). But to answer your question, me and a friend were on the train to Cologne last tuesday and were getting pissed about minecraft's wasted potential, and that nasty voice at the back of my head kept nagging me that I could do better.

Well, I'm on the same train ride exactly one week later, and lemme tell you how that went.

P.S. Code also available on github.

About

Minecraft takes place in a voxel world. That already holds a lot of potential - by reducing the fidelity of representation, it leaves details to the imagination, allowing for much more creativity with much less elements (like pixel art). To expand on that, it gives the player an infinite world - and that's where we hit upon the first issue. The world is infinite only in the horizontal, meaning we cannot have arbitrarily high mountains or wizard towers, or an ocean abyss or a pit that stretches down for eons. This seems odd - since the blocks are already arranged in chunks, what stops us from having those chunks be cubic and also stretching off infinitely above and below? It becomes rather tricky to generate worlds with infinite height, but that is also easily solved by having the worldgen be limited, and only building above or below if the player requests it - that is how the CubicChunks mod handles it for compatibility with vanilla worlds (yet as we'll see, mods don't solve our issue either).

Another issue is block types. A lot of mods add additional blocks with additional functionality, yet those are barely interoperable (later versions have become better at that, though not by much). Additional mobs, or behaviors wished for in servers, have to be either modded in tediously, or assembled from command blocks, which, while impressive, is rather Malborgian. The issue here, and the reason mods don't solve the problem, is that minecraft was not made to be modded. Dwarf Fortress, a long-time favorite of mine, provides, along with the executable, human-readable and -editable files defining all its blocks and creatures. If one wants to add a new element to the game, it is rather trivial with a simple text editor. Cataclysm: Dark Days Ahead also provides .json files for all its blocks, items, NPCs etc, and also takes a step further and provides the entire game code, allowing for any element of it to be changed and expanded upon as desired. Minecraft doesn't do either, only giving us a finished file that we are not supposed to modify. That not only quite hinders creativity, but means that many issues (seriously, horizontal chunks? in a 3d game?) can never be adressed properly.

With the current developments, it seems unlikely microshaft will ever release its grip on the code. And even if they did, it would require fundamental changes to all aspects of it for any changes/improvements to be made. It is much easier to write a clone, emulating the game where it succeeded and improving upon it where it did not, designed from scratch to be simple, modular, accessible, and free.

And most certainly not written in java. Ew.

P.S. Having multiple versions around shouldn't be an issue - computer systems are already plenty different, and interoperate flawlessly. Protocols can be designed around differences. If someone wanted to play with friends, it should be rather straight-forward for them to exchange whatever version of the code they have throughout the group. People already play modded minecraft together, we're simply making it easier for them.

Components

So, we're writing a minecraft clone - from scratch, with minimal libraries (man, I sure do that a lot, don't I). What do we need? Well, we'll need some base classes - a shared code base representing basic blocks (ha) to build our worlds from -, a noise library that generates said world, a rendering engine to display said world (and indeed anything else we might want to throw at it) to the player, and a network interface that allows us to share it with others. Those should be enough to have a very barebones version of our game, and should all be modular as to allow users to add, switch, and remove to/from them as they please to create whatever functionality they want.

Basetypes

Before we can even get to blocks, we'll first need a vector class (minimal libraries, remember?). Fortunately, we can get away with integers, using fixed point if needed.

That aside, the most fundamental building block (heh) of our game is the voxel. For ease of representation, the type of each will be an int (which means we'll have to use sequential assignment, but with over 64k possible types, we can get creative with hashing). Since we want those to be easily extensible, we'll make it its own class instead of typedefing ints.

From blocks we make chunks. We can theoretically have arbitrary many blocks in a chunk, we'll settle for 16x16x16. The main purpose of chunks is to serialise terrain generation and transmission, so we'll throw in some wrappers for those.

From chunks we make regions. This step isn't necessarily required, but is one of those things that turn out to be a good idea - storing chunks in a region allows us to traverse and serialise them much faster, making our game a lot more performant for a minor inconvenience in complexity.

From regions we can finally make a world. The world keeps track and manages its regions. []

To interact with that, we'll need a player entity. That will have a position (here we use the fixed point vectors) and an orientation (we can get away with using chars - it also allows us to hardcode trigs later on). We will not implement health or an inventory for the sake of keeping things simple - while those are useful game aspects, they are not necessary for our barebones edition.

Worldgen

Rendering engine

The most basic rendering engine takes slices of our world and prints them to the console. While that was quite useful for debugging the noise generators, it makes for a rather shit 3d game. Fortunately, making a mostly-working-kinda-look-it-gets-the-job-done rendering engine is rather easy - gather all faces that need rendering, perform some basic culling (the part that fucks up the most), project them to the screen, and render the triangles (that one deserved a separate function). Throw in some optional texture mapping and the ability to add arbitrary objects to the rendering pipeline, and we're golden.

Multiplayer utilities

I have to confess, I am not the networking type of person. []

Our game shall have a server and a client implementation. The server stores a world and its players, generating more of it as needed, and listens for requests from its clients, responding appropriately (for now, it won't validate them - merely accept and forward). It has no GUI - it is only the backend. The clients, differentiated via custom IDs, have copies of the world and players, and their main purpose is to simulate them for their player. Each interaction they do, they send to the server, and receive updates from it as to the other players. They will have their GUIs for the players to interact through.

The API is as follows: the first byte of a message denotes the sender of a message (the ID of a player, or 0 for the server / players requesting to join). This limits a server to 254 concurrent players, but that should be easily modifiable - adding one more byte would raise that limit to 65k, moving the limit to computational power. The second byte determines the type and further contents of the message:

One possible - in fact, recommended, but omitted for reasons of simplicity - improvement is to compress the chunk data in some way for chunk update packets. Validation has been omitted for mostly the same reasons, though should be easily implemented by having the server perform checks on the additional data of packet 0, or simply whitelisting client IPs.

Another interesting extension is to distribute the server functionality among multiple computers. With 251 more message types, it should be quite straight-forward to define message types for servers to interconnect and exchange information. Perhaps each only keeps track of a certain set of regions, forwarding packets and data back and forth until it resolves []

[should be possible to distribute computing among multiple servers] [could use higher byte messages to exchange information between the servers]