Welcome back to the Building a City Series, a series of blog entries on the open source release of SimCity (called Micropolis) and building up your own world with it. It’s been almost two years since the original release and a lot has happened in the codebase.
This entry is going to focus on the change to the codebase itself and a lap around what’s in the current source code, walking around the new Python UI, some talk about SWIG and what we’re doing (and why we’re doing it) and laying the foundation for some upcoming posts that are in the works.
Old and Busted
The Micropolis source code, when it was released as open source in 2008, was really two entities. The first is the original C code, ported to X11 by Don Hopkins, for the Unix operating system. SimCity was released for various *nix systems (Sun, X11, Indigo, etc.) and that code is what is the basis of what’s currently in the micropolis-activity folder in the subversion repository. This code was originally ported from the DOS-based SimCity that came out of Will Wright’s magical mind. However back then there was little concern for separation of concerns so much of the UI code is intermixed with the game logic and it’s all one big tangled set of dependencies that’s pretty hard to unravel. So Don took it upon himself (over the course of a few years) to unwind the logic of the system and put it into a set of source files where there is no user interface to stumble over when porting to other platforms. Enter the MicropolisCore project which is the current path of destruction in the codebase.
MicropolisCore is a set of C++ files compiled together which are then processed by a tool called SWIG (Simplified Wrapper and Interface Generator). SWIG was created for the sole purpose of being able to take C/C++ code, wrap it in a series of shadow output files (in the language of your choice) and use that code on various platforms and call it from more scriptable languages (Python, Perl, PHP, Tcl, etc.). After all, trying to prototype user interfaces or write things that are dynamically changing is no fun in C++ and frankly, the user interface toolkits for C++ are ugly and cumbersome.
Why bother wrapping all the code in SWIG just so you can build the UI in another language you might ask? The primary goal for Micropolis was to get it to the point where a new UI could be built (the initial release was for the OLPC program using the Sugar user interface). SWIG (along with the GTK bindings PyGTK) offers a way to build out that UI with platform independent Python scripts. The Python scripts for the current working copy of MicropolisCore are just that, scripts. You can quickly edit them and change the way the UI behaves but still be hooked up to the backend game engine through the SWIG wrappers calling into the original C++ code.
That’s the magic here. SWIG takes the original C++ code, processes it into a series of Python scripts (along with a C++ wrapper class to bridge the gap between the two languages). The pyMicropolis directory in the repository contains Python only code for making calls to that original Sim engine and letting it do it’s thing while the UI handles responses from the user and forwards those requests on to the C++ code.
SWIG wraps the C++ code but also provides a means for talking back to the calling language (in this case, Python). There are some callback functions defined in the SWIG interface file which handle the C callback function (named callback, you’ll find it in the stubs.cpp file in the Micropolis project). This is hooked up in Python so anytime the game engine makes a call to the callback method, Python code will be invoked and that handles dispatching the callback type to the appropriate function in the scripting language which then updates whatever view or control is attached to it.
When I said platform independence it really is just that. You’ll need to make sure you have a few things installed first (Python, PyGTK, GTK). Once you get a copy of the current codebase and have built the system for your platform (Windows, Mac, or Linux) go into the MicropolisCore/src directory.
On Linux run this “./run-gtkfrontend”. This Python script launches the PyGTK UI and produces this (running under Gnome on Debian):
On Windows run “python run-gtkfrontend” from the same directory, which produces this (running under Windows 7):
Both are using the same C++ files (MicropolisCore, compiled for that platform) and both are using the exact same Python scripts. Platform Coolness.
Wrap or Rewrite
Some might argue that porting all the original C code into a C++ class (yes, it’s a single God class called Micropolis) is crazy. However what’s probably more insane is having to go through, line by line, in the original C code and rip out the hard coded UI references and pull them into something more manageable. That ugliness was already done for you by Mr. Hopkins. Okay, it’s an ugly single C++ class and there are still a lot of “C” constructs in the code.
However it’s all in C++ code now and SWIG wraps it up pretty nicely. There’s very little Python specific code that had to be written to manage talking to the C++ code (really just the callback code and a few typemaps). To continue development on one platform or another (or another language) is pretty brainless at this point.
Could you go back and rewrite all the original C code into some kind of “portable” C. Perhaps. You would still have to rip out the UI specific calls to the Tcl/Tk toolkit and all of it’s ugliness. Then what do you do? Replace the Tcl code with calls to something portable like SDL? So now you’re swapping one technology for another.
SWIG was done for a reason, which was primarily to provide a means to build a new UI with something a little more scriptable than C or C++. At the time, Mono really hadn’t got to the maturity level it is now but then there’s still the Mac factor so rewriting in .NET isn’t the best option. SWIG doesn’t close the door on .NET (as you’ll see later) but there’s also work underway for a web based version.
Taking it to the Web!
Head on over to MicropolisOnline and you’ll see the initial seeds of the Micropolis Eduverse, an online version of Micropolis that’s being developed with an educational focus. The web based version (all of the source code can be found in the subversion repository) runs from a Python based web server using TurboGears for the backend (along with the SWIG-ified Python code from MicropolisCore) and OpenLaszlo for the front end (which is very XAML-like). There’s a working English and Dutch demo that you can play with from any web browser (although leaving your city up and running for a few hours tends to crash, the system is still in active development).
A Working Game, Almost
Getting back to the desktop version, the current MicropolisCore code is vastly improved from the test scripts we created last year. When you launch the GTK frontend you get a splash screen that lets you a) choose from a pre-determined set of scenarios (each with a “win” situation, just like the original SimCity game) b) load a city from the “cities” folder or c) keep clicking the Generate City button to randomly create a city to play with.
Once inside the simulator you’ll see changes from both the original “test” code we did and even the original Tcl/X11 user interface. Here’s the game screen under Windows after I put down a few roads, power lines, and zones:
Things you can do with this build using the current PyGTK interface:
- Start a new game
- Load cities
- Load scenarios
- Generate new cities
- Lay infrastructure
- Rail lines
- Power lines
- Building Tools
- Nuclear and Coal power plants
- Stadiums and Parks
- Zone Tools
- Residential, Commercial, Industrial zones
- Police and Fire Departments
Most of the tools are accessed via a pie menu which gives you quick access to building tools, zones, and other elements. The pie menu is completely implemented in Python (using GTK for the UI) and talks back to the game engine to invoke the appropriate tool (again, through callbacks). You can find all the pie menu code in the pyMicropolis/piemenu directory.
The simulator runs and you can control a lot of aspects of it. These are accessible from a series of tabs across the top. Each tab either displays some information from the game engine or allows you to control some aspect of it.
This contains any notifications from the system (the first one being when you reach a population of 2,000) and replaces the old annoying pop-up screen you would see. Like the old popups? Then make a change in the micropolisnoticeview.py file and modify the updateMessage method (a simple popup could be used like gtk.MessageDialog).
The Messages tab contains a scrolling list of short notifications that the game has sent to the UI via the callback function.
This panel shows a brief summary of how you’re doing. It’s updated frequently from various places in the engine (most often updated at year end when all the calculations are done for taxes, people immigrate in and out of your city, etc.).
The History tab keeps a running total of all the various zones and stats about your city including crime rate, pollution, and cash flow. It shows both 10 years of history and 120 years (click on the button to see each graph) and is updated live as the sim runs. Here’s the 10 year view:
This panel shows you what your current budget is running at and allows you to tweak values in real-time with the engine using a slider control.
The map is a really interesting tab as it lets you overlap various aspects of your city on top of the main window. It uses cairo (and the Python bindings via PyCairo) to blend colours over the tiles rather than the harsh 1 color / 1 pixel approach you see in SimCity classic (or even the SimCity for Windows game). For example here’s the Power Grid overlap on our map which shows power distribution for the city.
What’s a SimCity game without disasters? This panel lets you unleash a tornado on your Sims or melt down your nuclear power plant. All of the buttons here work so go ahead and kill off a few million residents.
This panel lets you tweak some aspects of the game like how fast it runs, what options are turned on or off (disasters, animation, etc.). It also contains some buttons that will take you back to the splash screen and allow you to change to a different city or load a scenario. Note: There is no “Are you sure” type option here yet so you might lose your current city if you’re not careful.
Like I said, it’s almost a working game (playable but not 100% there). I would say the current Python implementation does about 80% what the original game did. There are still a few gaps but those can be easily filled with a few UI enhancements. There are also a few “gaps” in the engine that have yet to be coded. For a list of TODOs check it out the files in the root of the repository here.
No, it’s not pretty. It’s an open source project built by geeks. Give it some time and if there are any graphic designers out there willing to spice up the UI let us know.
Abandoning the Past
Like I said at the beginning of this post, there are really two parts to the codebase. There’s micropolis-activity, the X11/Unix system that’s the original C code (with tight hooks into the Tcl/Tk libraries to do the UI) and there’s MicropolisCore which is the C++ code, SWIG wrappers and Python bindings that form the Python/GTK/Cairo desktop version.
You can pretty much consider the micropolis-activity code abandoned-in-place. I noticed recently on the (unstable) Debian mailing list a new patch to fix some problems with the X11 code. Someone will probably fold these fixes into the repository but for the most part nobody is actively working on it. Also the desktop portion of MicropolisCore won’t be going too much farther (at least by Don). He’s focusing on the web front end (which is all OpenLaszlo). We’ll still be updating the MicropolisCore C++ code and updating the Python wrappers as we add new functionality (or fix old ones) but there won’t be too much progress on the PyGTK frontend.
The Future is Bright
If you do check out the latest copy of trunk from source control, you might notice a few new changes. First off, the Visual Studio solution has been upgraded to 2008 (with a 2010 version coming out when it ships). There’s a new “CSharp Release” configuration in the solution. Changing to this and rebuilding the solution will kick off SWIG and produce C# wrappers for the C++ code (and copy all the generated files into the right locations). There’s also a new C# project called MicropolisClient which is a WinForms client I created to mimic the gtk-frontend (it actually creates an executable called cs-frontend in the same directory). It contains a folder called MicropolisEngine which holds all the generated files from SWIG. Once the client is built it launches the engine and (will eventually) provide a WinForms .NET front end to the simulator (it doesn’t do a lot right now as it’s in development and the callback mechanism back into C# isn’t written yet like it is with the Python code).
There’s a lot of work to do on the C# client that’s already done in the PyGTK version. The Python version also has the benefit of using the TileEngine project (and it’s Python wrappers) which is an independent tile system for rendering the Micropolis cityscape. I chose not to wrap this project in C# because it relies on the Cairo library and I really didn’t want to put any dependencies on 3rd party libraries for rendering graphics. The C# version is going to use GDI+ for it’s rendering or if that doesn’t pan out, DirectX (or possibly XNA). Basically you won’t have to install anything other than the Micropolis binaries on a Windows box to run it using this front end. Another option is to create a WPF frontend instead of WinForms as the graphical look and feel might be easier with XAML and there’s more flexibility with regards to image manipulation and WPF. Adventurists can feel free to use the current build as a basis to write a console version of Micropolis in C# (kidding!).
In any case, the current source code builds for Linux, Mac, and Windows and produces a nice, playable simulator you can play around with.
Where we go from here is up to you.
This is a series of posts exploring and extending the Micropolis code. You can view the full list of posts here.