Tuesday, May 24, 2011

Scripting

Luabind is awesome.

I've spent some time with this library, and it's a really amazing C++ wrapper for Lua. Binding functions, classes, even callbacks and anonymous functions, it's a breeze.

Materials were never supposed to be hardcoded, but now the framework finally allows you to specify your own in a Lua script:

define_material(1, { name = "dirt", texture = { 1 }, hardness = 1.5 })
define_material(2, { name = "grass", texture =  { 1, 0, 1 } })
define_material(3, { name = "water", texture =  { 239 }, transparency = 0.5, viscosity = 0.2 })

...And so on. My first idea was to read this from the world database, or an XML file, but nothing is as convenient and flexible as this.

(The "texture" property is an array with 1 to 6 indices to the texture atlas. If only one value is given, all faces of the cube will use that texture. In the case of grass, texture '1' is used for the sides, '0' for the top, and '1' again for the bottom. An array with 6 values would specify different textures for every face.)

Strictly speaking, this isn't real scripting yet, just configuration. So let's take a look at events:

function launch (player)
    player:change_speed(0,0,10)
    player:shout("WHEE!")
end

on_approach(40, 40, 0, 3, 6, launch)

On_approach calls a function whenever a player gets near (40, 40, 0), within 3 blocks distance. (The coordinates are given relative to the center of the world). Any player entering this area will be launched into the air, by adding 10 m/s to their vertical speed. This event won't fire again until the player is further away than 6 blocks.

Similar triggers could be added to materials, items, and mobs. This, for example...

define_material(2, { on_touch = launch })

would be really, really annoying. But it would not overwrite anything from the first definition, it would only add a trigger.

Next thing I'll need to do is look at security. It's very important that the scripts are properly sandboxed. Also, I should study Gary's Mod, to get an idea of how to properly design such an API.


Edit: I'm jotting down some ideas here.

Saturday, May 21, 2011

More screenies

So, people wanted to see more screenshots! Let's take a look at the first two steps of the terrain generator:


The first step uses 2-D perlin noise to generate a height map. Nothing fancy.


The second step mi-... WHAT.

*fixes bug*


The second step mixes in 3-D perlin noise in some places. (This whole "in some places" bit will be fleshed out later into a nice, flexible biome system). The general shape of the terrain is still the same as in the first picture, though.

3-D Perlin noise is, simply put, a function that takes an x,y,z position as its input, and returns a value beween -1.0 and 1.0. It is a bit like measuring the temperature at a given point. For two positions that are right next to eachother, the returned values will be almost the same. But two points far apart will return completely unrelated values. This value is multiplied by some factor, 30 in this case.

Once we have this value, we subtract the relative height of that point to the surface that was generated in step 1.  If the result is positive, a block of grass or dirt is placed. If not, it's air.  The end result is some weird craggy terrain, and some floating boulders.

The same valley, seen from the other side:



And some steeper terrain, while we're at it.



Thursday, May 19, 2011

Bigass dragon invades Broville

The Minecraft world reader used to be a storage module. So instead of the usual Sqlite database, the game would read and write all terrain data to a Minecraft save game. I have upgraded it to be a proper world generator, so I can combine it with other generators (and go back to the much faster sqlite for storage).


This screenshot shows the game running with three generators: infinite flatland, Broville, and the Binvox reader. Now that the basic framework is in place, I can move on to creating more interesting generators, such as a tree planter, a cave digger, rivers, etc. ("Interesting" in the sense that they use the output of the previous modules. The ones shown here just superimpose their data, much like the layers in Photoshop.)

A few major changes under the hood: the world is now 4,294,967,296 blocks in every direction, including height. The old limitation of 65,536 blocks still applies to some terrain generators, though.  

A lot of the code now uses Boost threadpool, a not-yet official library for dividing up work across multiple threads. It works great on my 4 cores, although the code for feeding the results back to OpenGL is still a bit ugly. The result runs very smooth, but glitchy as well. Ergh, concurrency bugs... *headdesk*

Edit:
More screenies, yay.





I just noticed in that last screenie that one of the Minecraft chunks missing. The shadow inside that square hole looks great though. ;P

Had a couple of deadlocks and spontaneous suicides in the client while flying around. Holy shit this needs some serious debugging. Also, a little noclip screenshot to show that there are still caves underneath all this: