We’re approaching the 0.4 release fairly soon, which is going to be the start of “hey, you can write a game with this.”
Basically, we’re at the point where I can say that we’re including a full game framework in 0.4. Personally, I think it’s pretty slick. Maps are composed of Pages, which are 3-D blocks composed of Squares. Entities (which are left very vague–players, monsters, items, and trees would all be entities, although you might want trees to actually be Squares based on your game model) travel on squares, and are seamlessly handed off between Pages. The reason there’s a segmentation of the map into Pages is to allow the implementation of two features: caching and scheduling. There’s also a cool third feature to talk about, which is messaging.
First, scheduling. For most large-scale “world simulator” roguelikes, it’s not simple to multithread them for performance (often because it wasn’t designed to be parallelized to begin with) With Sharplike…it pretty much is simple, at least for the end developer. Maps are scalable; we will be using threadpools to run as many threads updating individual pages as is reasonably possible on your hardware (so multi-core computers will see a near-linear speed increase–dual-core, double the simulation performance) Stuff like entities or fluids would be handled by this system, which should demonstrate fairly large perf improvements over the standard “single-thread EVERYTHING!” approach that many other engines use. Entities will use a global timer and a Delay value, so objects will be able to “skip their turn” if they don’t need to be checked every game tick/step.
The obvious problem here is performance. Even threaded, you could have hundreds of thousands of objects that need going-over, over hundreds or thousands of pages. This is, shall we say…not speedy. To this end we’re implementing a caching mechanism, which both allows conservation of memory and CPU time. Pages exist for caching: each page can be cached a specified way. Caching has three states: Hot, Warm, and Cold. Hot states are “active” and in RAM; they’re simulated every game step. Warm ones are in RAM, but simulated only on certain steps–up to you to figure out what’s right for your game for that. Cold pages are stored on-disk in serialized format – they aren’t simulated at all. The system will allow you to specify what should and shouldn’t be cached, to allow for fast transitions. (For example, in a walk-around-a-really-big-world roguelike, you could specify that everything within a 5-page square around the player should be hot, and a 2-square radius past that should be warm, and everything else will be cold. So it transitions from warm to cold as the player moves, loading into RAM well before it’s necessary in the game.)
The third feature is messaging. Anything that implements the IMessageReceiver interface–by default, the Game class, the Map class, the Page class, and all entities–can define a global name for themselves (it’s optional), and set up to receive messages from other objects. Messages are passed hierarchically, so if you’re sending it to an entity on the same Page, it doesn’t traverse up to Map-level before getting to the correct place. There’s also the Message Channel system – objects that implement IMessageReceiver can subscribe to a channel and all of them, game-wide, will receive them at once. This is nearly required with our multithreaded scheduling model, and will require a little practice for programmers to harness correctly, but it’s relatively fast and very scalable. And while 0.4 may not include realtime game capabilities, once they’re there it’ll work pretty much out-of-the-box.
We’ve also significantly improved our UI system, but Sean or Alex can talk about that.