This Week In Veloren 30
Thanks to all of the contributors this week, @Timo, @Sharp, @Zesterer, @Vechro, @Slipped, @Demonic, @Pfau, @cauthmann, and @Songtronix!
Thanks to @lobster for this week's Screenshot Saturday. We're excited to see what comes out next week!
Programming
Jungle Biomes by @Sharp
For my first contribution to Veloren, I decided to make jungle biomes, which have been a popular request. I was told that that wouldn't be an easy task, because we would need to add humidity and it would require a major refactor of the worldgen system to be more modular. Well... it didn't, but it was a lot more work than I expected.
Besides jungles themselves (which are mostly credited to the great work of Veloren's asset designers, and have nothing to do with me!), the key contributions of the new patch were (1) adding humidity, and (2) using more principled statistical distributions for controlling factors like temperature, humidity, and tree density.
For the first of these, I just used another procedural generation method, billow noise, but something didn't feel right. What I was generating didn't look like jungles, just groups of trees. Not only that, it felt like however, I tweaked it, either the whole world was mostly jungles, or they were barely anywhere. And every time I tweaked the noise a bit, the distribution of everything changed and I had to go through the whole world looking to make sure everything still looked okay!
So I did some reading about statistical distributions (normally I would have hated this, but it's amazing what working on a game will do for you!). It turns out that a key part of the culprit is that we wanted to make humidity go down with altitude. It turns out that when you add or average multiple random variables together, even if they are uniformly distributed along a range, meaning every value in the range is equally likely, they will more and more approximate a normal distribution. That means that "moderate" values are more likely and "extreme" values are less likely, which means that it can be hard to predict how many of the "extreme" climates you'll actually see in a (relatively) small world like Veloren's.
What's worse, it soon became apparent that the procedural noise functions are not even close to being uniformly distributed, meaning we have absolutely no idea what adding them together will do or what effect tweaking their shape will have. That's pretty bad because it makes it very hard to tweak the shape of things like the altitude generation or temperature without destroying biodiversity, even if you do end up getting some of the factors right.
So what solutions do we have? It turns out that there is a way to turn a distribution back into a uniform distribution, as long as you can compute a certain key function that describes the distribution (its "cumulative density function"). Even better, it turns out that for some kinds of distributions that we wanted to use, there is a closed-form solution for this function! A key use of this would be a logistic distribution which we wanted to use for tree density, and the weighted sum of uniform distributions, which we wanted to use for temperature and humidity.
All that remained was to implement this solution for the functions we knew. But what about all the procedural noise functions? It turns out that figuring out any sort of closed-form solution for these is an open research problem -- like very open. In the end, rather than solving it, I decided to just take advantage of the fact that we have a closed world, and "brute force" the cumulative density function by going through all the computed values, sorting them, and using their positions in the sorted list as their uniform value. This is basically the idea behind cumulative density functions, so it's not as lame as it seems, but it does mean that this particular solution can't be used with an infinite world.
After all this math, there was still the matter of making things look visually pleasing. For this, I have @Zesterer to thank for patiently guiding me through how to make transitions between different humidity levels and temperatures aesthetically pleasing. Particularly difficult was getting the "snow splatter" effect to work when you no longer want snow except at certain humidity levels. I also have a very poor sense of what colors to use, which led to a lot of entertaining back-and-forth. So, by the end of all this, I was hoping that it would end up being worth it. Was it? I think so... but you decide :)
Town Generation by @Zesterer
We'd like to have nice town generation in Veloren. Plenty of voxel games have them, but few do them well, for a few reasons:
Most town generation algorithms require expensive pre-generation of the surrounding landscape before generating the town itself, thereby limiting the upper size of the town
Town generation algorithms that don't require the above tend to produce bland or uninteresting towns with little integration between their various parts.
Veloren solves these problems in two parts:
Pre-generate the entire world at a lower resolution
Pre-generate the entire town on top of the world at a lower resolution
What does this give us? First, it means that each town might be implicitly aware of neighbouring towns during the world simulation state. This will permit us to:
Simulate economic resources flowing between towns through trade
Simulate the migration of populations between towns and the effect their settlement may have on the towns
Simulate war between conflicting towns and civilizations
Secondly, it means that we don't need to do expensive pre-generation of the surrounding terrain because we already have low-resolution information about the terrain. It's not perfect, but it's more than enough to generate bits of the town in a visually-pleasing manner.
In conclusion, town generation goes through multiple distinct stages:
World generation (low resolution)
Town generation (low resolution)
World simulation (low resolution)
Chunk generation (block resolution)
At each stage, more and more detail is added to the world. The final stage, which occurs in real-time while the game is running, takes the existing metadata generated by previous stages and turns it into the raw blocks that we show players in-game.
Other work
@Pfau has been assisting with the town generation from an artistic side. Houses will be made from 9x9x9 blocks that make up the components of the structure. He has also added mushrooms and the current time of day in the debug view. He is also working on adding more to the new jungle biome.
On top of what @Sharp worked on earlier, they also did some initial work on river generation and erosion. @Timo worked on pushing combat forward. They implemented a new struct to keep track of what a character is currently doing.
struct CharacterState {
movement: MovementState,
action: ActionState
}
enum MovementState {
Run,
Roll,
Jump,
}
enum ActionState {
Idle,
Wield,
Attack,
}
@Timo added a new ActionState Block so a player can defend themselves against incoming attacks. I wrote the code that reduces damage while blocking by 90% and @Slipped provided a fitting animation. They also added better aiming, so you now have to hover your crosshair near the enemies body to hit him, not just in the general direction. The player now looks in the direction the camera is pointing at while in combat to make aiming more natural.