I think after 2.5 years of development (6 years if you include the java version) it’s about time I share it with you:
On the surface Cubyz is just like any other minecraft clone. You got blocks that you can break and place.
But if you look further (and deeper) you will see that Cubyz has more to offer:
- With LOD you can see the world in its true scale. In fact the render distance is so big, that I have to use in-memory compression.
- There are no height limits, allowing to venture into the deep unknowns. There are many unexpected biomes waiting to be discovered. And if you think you’ve seen it all, think again.
- The procedural crafting system, based on a 5×5 grid, allows you to craft any tool you can imagine, whether its useful or not.
- For building there are many cool options, like the ability to chisel away corners of a blocks.
- Using UDP hole punching you can invite people directly into your game, without doing a bunch of stupid stuff, like configuring port forwarding.
- With some simple ZON files, you can easily add your own biomes to the game. I try to make it as configurable as possible, so that you could truly change the game with this.
Now, since this is a Zig forum, I’d like to use the opportunity to also share some Zig-related details:
I think the most interesting things are my allocation strategy, and how I’m breaking the zig zen
:
My allocation strategy is basically an extension of the global allocator strategy you see in most other programming languages. I use mainly two allocators:
- I use a stack-like
threadlocal
allocator for local allocations that get freed at the end of the function. I use a slight extension of the normal stack that allows for out-of-order frees, so this allocator can even handle lists and stuff. To make sure that I don’t run out of memory it is backed by the global allocator. - I use a single, global GPA for everything else (minus some arenas and memory pools for specific things). It’s kind of bad at the moment, but I’m banking on that faster allocator implementation in the future.
A while ago I discovered that my error handling was terrible. I was rarely handling errors, and most of the time I was just being lazy and bubbled them into the main, never to be used again. I discovered that the root cause of this was all the noise that are allocator errors. Every time I allocate something I have to deal with this once-in-a-lifetime error, so of course my default is to just bubble it up the chain and crash.
This got me thinking, and I noticed that most of my allocators were relying or fall back on a single global GPA anyways. But the thing is: Even if I run out of memory the GPA won’t even fail reliably (at least not on linux because of memory overcommitting).
So to recap: Everywhere in my code I carried around an error, that basically never happens, but is indistinguishable from other errors making it difficult to implement proper error handling.
That’s why I decided to just get rid of it, by shipping my own ArrayList and my own allocator interface (which is just a shallow wrapper around the std one so I can still use it in std functionality that I don’t want to implement myself). Nowadays I am handling all of my errors locally, either in the same function or just a few functions up in the call stack.
If you want to see more you can check out the source code on github.
To run it you just need to follow the steps in the readme. There is a script that can download the correct zig version for you, so this is fairly straight-forward.
If you want to play or just chat with me or other players, you can join the discord server where I regularly (usually once a week) host a multiplayer world.
If you want to see more of the game and its history, I also have a youtube channel where I make some devlogs every couple of months.
And if you got any questions you can also ask them below of course.