No Time To Play

Building a Game Application Server (Part 1)

by on May.12, 2011, under Gamedev

So … as promised in my last post, I’m going to start a series of “how to build your game application server”.  The first step is to figure out, in general what you want to make.  Then, the next step is to get a sense of your architecture.  How are your components going to fit together and communicate with each-other?  What interpreted language will you use, and what underlying “lower level” language will you use to support it

For this series of examples, I’m going to take you through building a multiplayer server which would be suitable for running a MUD/MUCK or a multi-player tile based game like EUO or Shattered Moon’s Ultima IV multiplayer.

In truth, the interpreted language and the “lower level” language you choose is largely preference.  There are some more suited to the task than others — Lua and Squirrel were mentioned last time as two languages specifically designed to be embedded.  Python is another choice, and has the benefit of being a full fledged language on its own but still easily integratable.  It’s also down the down side of being a full fledged language on its own; it will tend to be more resource hungry and “slower” than some of the other options.

The underlying language must support your “higher level” language and it must offer high performance as well.  The whole reason we’re bothering with this architecture is to combine the ease of programming in a script language with the speed of a more difficult to use language like C or C++.  Think of the high performance code as “critical sections” that will be called by your script layer to do things like render graphics and interact with hardware.  Good threading support is also important.

So therefore, you may be restricted to C or C++ for the foundations of the application server.  Java also has good support for embedded languages (See Jepp, Kahlua, and Mochalua among many others) but it probably won’t have the hardware level performance that you want.  Some of the readers of this site and fellow contributors may know even more language options, as I admit my palette is somewhat small in this regard!

For my examples, I’m going to use C and Python.  Why C?  Because I know it inside and out, it’s high performance, and it integrates easily with Python.  Why Python?  Because it comes out of the box powerful with many features that you may have to implement on your own in a leaner language.  Plus, I don’t think the performance hit is that bad; anything that needs to be speedy we can offload to C, anything that needs to be tweakable can be offloaded to Python.  And ultimately, it’s also a heaping helping of personal preference.

Now that we have that settled, let’s draw a little diagram of how this will work:

Please try to forgive my rather ugly MS Paint-built info-graphic!  So, basically, only the top box is Python.  The rest is C.  Each box may optionally be a thread with the lines then being thread-safe queues; if threads are not used, then the lines are merely function calls.  Let’s go into that in more detail.

Threads are great things when you use them properly, and they’re nightmares when you use them incorrectly.  True of many things, but especially true of threads because they are a very easy way to lock up your program without being able to determine why or how very easily.  In games, threads are often avoided; they’re becoming more and more common, but generally speaking in a single player game you can go pretty far without having to use threads.  However, once you start building in multi-player or super-heavy graphics or any number of other similar features, you’ll start having issues where parts of your game can block other parts.

That’s where threads come in.  Consider the places where your game may get blocked or may need time to wait that should not block the rest of the process, and spin those off as threads.  For a multiplayer server, it’s pretty important that the network (the I/O box) be it’s own thread.  Also my “bridge” and interpreted language will be, together, it’s own thread.  Database and system I/O I will leave as function calls; for this sort of game, I’m not expecting a lot of blocking time there.

If you were making a single player game, you could avoid using threads altogether.  In fact, even in this example, threads could be largely avoided.  But that actually makes it harder to program in some ways — hopefully I can guide you through it okay!

One more thing to point out; what, exactly, is the “bridge” I just mentioned?  Most interpreted language integrations (probably all of them!) work based on callbacks.  You provide functions that the interpreted language calls when it wants this or that.  I refer to the set of callbacks, which are often wrappers for lower level calls, collectively as the language bridge.  The bridge also contains and bootstrapping needed to get the language started and running on it’s own thread (if you’re doing that sort of thing).

So that’s an extremely sweeping, high level look at what we’re going to build.  Next article, we’ll actually get into some code.  Am I going a little fast?  You bet!  Feel free to ask questions.


1 Comment for this entry

  • fluffy

    Python’s slowness has nothing to do with the size of its runtime library (and don’t confuse runtime library with the language itself – Lua and Javascript are both as fully-fledged languages as Python, they just don’t come with as many libraries built-in) and everything to do with how its interpreter and garbage collector are just plain slow. Lua and Javascript both have the advantage of varying levels of bytecode compilation, and the fastest Javascript engines will even JIT down to native code.

    Also, for a game server, often you want a lean-and-mean runtime library if only due to security concerns, especially if users can run their own custom scripts (as on a MUCK or MUSH). You really don’t want a user script to be able to, say, open a shell or dump files that are owned by the game server process or whatever.

    One of the things I liked about Tcl was that it had an easy-to-enable “sandbox” mode which would disable every builtin that can access things outside of the scripting environment itself, and it had an easy mechanism for further restricting other builtins (such disabling for and while, if you wanted to guarantee the halting-ness of a user script – recursion had a stack size limit, of course, and any other iteration was easy to do using foreach) or enabling ones that were needed by user scripts after all.

    Of course, any good game scripting language should have the ability to support multiple threads of execution (in the generic “I can pause this task and resume it later” sense, not necessarily meaning that tasks can be preemptively or concurrently scheduled) and the ability to abort those threads based on fine-grained criteria such as memory usage and time taken.

    I know Python does have enough support for threading that such things wouldn’t be so hard to implement in the game server, as does Rhino (a Javascript compiler for Java), but I just don’t know enough about Lua and the like to know if they do. I do know that dealing with those issues in the various other Javascript interpreters (namely JavascriptCore and V8) are ridiculously cumbersome, because they don’t have any built-in threading (or even thread-safety) and so you have to be very careful with e.g. running Javascript in one thread and having a monitor thread try to kill a task that’s taking too much of some resource.

3 Trackbacks / Pingbacks for this entry

Posts by date

May 2011
« Apr   Jun »

Posts by month