Game Development Team Primary Role: Configuration Manager/Software Engineer
We had our closing party/presentation today. Some of the family of the students involved were there.
This was what I spoke today, in front of the group, at the spectacle. The formatting and punctuation was to help me find my place and speak it with the proper emphasis. Except, here, there is way too much whitespace in between the lines. That's just the default css in the page and it's way to tricky to fix it.
My name is Ian Trick.
I was asked to briefly speak about the software architecture of project. This is that:
We used a programming language called Python, a game development library called Pygame, and a physics engine called Pymunk.
Pymunk, was slow and buggy.
Pygame, was slow and buggy and old.
Python, is awesome.
Our selection of tools may suggest that a lack of foresight went into our decision. Which is correct.
But, the lack of stability and hand-holding that you might get from a commercial high-level software development package, that does all the work for you,
helped teach us to deal with the kind of low-level problems that really require you to learn something.
So, in a lot cases, what appeared to be a lack of thoughtfulness in our choices ended up being fundamental to our education.
The accomplishment that I am most proud of, was implementing a system for rudimentary bug reporting.
The feature is designed to be activated when the game starts crashing on an end user's machine. It compiles a report, based on the nature of the error it encounters, and sends that to one of our servers where its accessible to our developers.
This was a feature that I crafted with lots of careful thought and consideration. It's a mechanic that depends on the successful operation of more than, just, a single machine or software.
It requires interaction between clients and one server.
And an interesting consideration of this relationship is security. In a professional context, this would be quite important. For this game, my interest was exclusively pleasure.
I challenged myself to devise methods to circumvent exploits inherent in using a network. And educated myself on the very basics of security engineering.
And, today, I am very satisfied with my efforts.
Regardless of how underutilized my contraption has been. What I gained in knowledge is justification alone.
And it is critical to remember that the work I did on this, and throughout this project, was made possible by the infrastructure of this course - and how it encourages application and practice and not just theory.
I'd like to finish by saying that, during my involvement in this course over the past three semesters -
I have faced impressive social _and_ technical challenges.
And throughout this process, I uncovered flaws in myself that I didn't know existed and discovered abilities I didn't know I had.
I changed in ways that I entirely did not anticipate.
And I believe that I will not fully grasp the value of this project for quite some time.
But I think, maybe, the idea that will be most valuable -
is that with the appropriate perception and attitude towards the things that we face
a challenge can be synonymous with an opportunity.
I gave a short presentation today. When I set out to write the spoken component, I ended up having to rewrite my work three times. Each time, reducing the scope and depth of my draft. I saved the first revision, because it covers interesting topics and, although it is not suitable as the body of a short speech, it can make a good blag post.
My next post will be the final draft; what I spoke today at the presentation.
The following is that draft; the first half is written for people who are not particularly technical.
One problem with our situation is that we have a lack of beta testers. Given our numbers, there is a limited amount of play testing that we can do ourselves. To maximize stability in our game, we need to find the less obvious flaws. The kind that only reveal themselves under conditions that end users can conceive. So the problem to tackle then becomes, how do we discover how our software is performing in the hands of our users.
A really handy thing about Python, the programming language we're using, is whenever something goes wrong, it creates what’s called a traceback and includes a lot of neat information about the environment that caused the error.
So, I set out to produce a nifty system in our game that would collect and organize that information.
The error reporting mechanism, that I made, can be broken down into two components; the server and the client. The client is everything in the game itself responsible for collecting and sending information to the server. The server is the system that receives, parses, stores, and organizes the information, making it accessible to developers.
Implementing the actual functionality was quite straightforward. I used existing infrastructure - like HTTP, the protocol generally used when you visit a website - and libraries in Python for making requests over HTTP. The server was built in Python using a framework called Django, which lets you quickly build an HTTP server - complete with a database.
So, the basic infrastructure was easy to assemble. But, in a "real world" application, just the basic infrastructure would not suffice; the dimension of security must be considered. The challenge I faced was the following scenario:
If someone monitored the network traffic coming too and from the game running on their computer, they could easily discover that it's making an HTTP request to a server. With that information they could mimic the request and send malicious information.
Disregarding the likelihood of this ever happening to us in this context, I set out to find a solution to the potential of the exploit.
I began with the premise that we needed the clients to do, was send some additional information for authentication. So, the functionality that I wanted to reproduce here, was one that was similar to password-based authentication. However, the system must be responsible for providing the password, since no user interaction can be provided. Another thing that was key, because of the exploit mentioned above, was that the password-like value could not be transmitted over the network. Instead, there needed to be some mechanic that showed that a client knew the password, without explicitly stating it.
I considered modeling the authentication system based on that used at the Bridge of Death, where Arthur and his party try to cross the Gorge of Eternal Peril in Monty Python and the Holy Grail. However, I recalled how that turned out for the bridge keeper and decided against it.
So, instead, I speculated that the client needed to receive a unique value from the server, operate on it in a way that produces a particular result depending on the “password” that it knows, and send that result back to the server. After snooping around on the wikipedia, I discovered that something called a cryptographic nonce was pretty close to what I was looking for.
Based on the idea of a cryptographic nonce, my implementation goes like this; the client makes a request to the server and receives a nonce. Then, on both the server and the client, a sha256 hash is performed on the nonce mixed with salt (which acts as the “password”) to obtain a result which the server uses to verify the client’s report. When the client sends an error report, it includes the result of the hash. The report is accepted if and only if the hash result from the client exists in the database of results that the server calculated in the previous seven seconds.
This tactic is not perfect; but, it moves authentication from being visible on the wire to happening only at the endpoints where it’s less visible. And it prevents spoofing error reports from duplication because each nonce result can only be used once.
One problem with this implementation is that it is impossible to capture a report on its way out, modify it, and resend it with the valid result that it was compiled with. Since the first report was prevented from being sent, the server doesn’t detect the altered report as a copy. To solve this, we can apply the hash operation on the report data when we compile it. Such that, when the server receives the report, it can apply the same operation and confirm that the report has not been tampered with since that the result that the server obtains will be the same as the result from the client if and only if they are calculated from the same data. In fact, if we do this, I don’t think we don’t even really need the nonce in the first place. So, it seems to be a better solution entirely.
That concludes my discussion on security. To finish up, I’ll briefly cover the neat-o-ness of the Django site I have configured. When the game runs for the first time, it creates a random string which acts as the user id. So we can detect if one user encounters a particular kind of error recurrently, or discriminate between lots of the same kind of error across lots of different people or lots of the same kind of error from just one person. The server also does a bit of parsing with regular expression to find the file containing the line that threw the exception. And version information and the date and time of the error are also collected. Using this data, and Django’s magic, I had a tool for filtering and sorting through high-level diagnostic output.
I'm having trouble coming up with good titles. This post is about how I set up bridged networking for a virtual machine running under kvm using libvirt on Arch Linux. But, before that, I'll elaborate on some background. If you'd like to skip that, here is a link to the good part.
I have been given the role of the 'configuration manager'. In addition to maintaining the mercurial repository and setting up Trac, I created a build bot for nightly releases and set it up in a Windows virtual machine running on a Linux server box at home. Origionally, the build bot was running on Ubuntu. However, the upgrade to Ubuntu 11.04 crippled the OS. I took this fresh start as an opportunity to try Arch Linux again.
In the past, I have had poor success with retaining a stable system running Arch Linux. But, I believe, most of the stability problems I faced were a result of the wireless drivers I used. In this case, the computer is a server with only wired connectivity; no wireless drivers are required. So, I thought I'd give Arch another try.
On Ubuntu, there was enough information on the internet to figure out how to make a bridge without much hassle. However, Arch Linux's infastructure is a bit different, and there were no up-to-date guides specifically addressing my situation. Furthermore, setting up the bridge previously was such a trivial matter that I didn't really recall what I did to make it work.
Eventually, I found out what I did before, figured out why it didn't work on arch, figured out what to do instead, and I did it. The factor that required that kind of drawn out process was that Arch Linux is a fairly rapidly changing platform. Many things that were mentioned in guides for Ubuntu, or in guides for Arch written years ago, were depricated and do not exist in Arch Linux today. The bleeing edge, community driven, attitude of Arch, that was responsible for this side-effect, has drawbacks - seen here - and advantages. In the end, the whole deal was a lot of fun. And it was worth it.
Disclaimer: I may be missing some bits here and there. These instructions were not tested on a new machine, they are a compilation of - what I speculate are - the most valuable parts of the process I took in setting up the bridge.
I think, the only package I needed was uml_utilities. Although, bridge-utils may be required as well.
I'm pretty sure some kernel modules are required.
# modprobe bridge # modprobe tun
And you should put them in /etc/rc.conf so they are loaded when you boot up. So something like...
MODULES=(... bridge tun)
The next set of alterations I made was an addition of the file /etc/network.d/vm_bridge.
INTERFACE="br0" CONNECTION="bridge" DESCRIPTION="herp de derp" BRIDGE_INTERFACES="eth0 tap0" IP="dhcp"
NB: This, assumes that eth0 is the device you're bridging over.
This adds a profile that you can control a little bit with netcfg. The profile is named vm_bridge, but you can set it to whatever you want via the filename.
Before starting the profile, I think you need to add the tap device. I'm pretty sure it's just:
tunctl
It should give some output telling you that a tap0 or something interface has been added.
The profile probably isn't started by default, so you'll have to run netcfg -u vm_bridge to bring the interface up.
Afterwards, you'll need to get your virtual manager to use the br0 device. This is fairly straightforward with the gui provided by the virt-manager command. What you'll need to do is add a NIC, and specify the shared device name as the interface name specified in the profile, in this case, br0.
I'm pretty sure that's it. Again, I haven't tested this from scratch on a new machine; I haven't had the time. If I get around to it, it would make sense for me to update this; however, the way this posting thingy works is that if I ever modify a published post, the published date is updated as well, such that it's as if my update is the first time that page has been published. On the other hand, it doesn't seem to make sense to put corrections for this in another post. So, I'm not sure what I'll do. But, I probably won't get around to refining the process anyway, so the particulars are irrelevant!
We've moved into the final semester of this project, and our team has shrunk, as some individuals did not continue the course into this semester. As a result, roles became unfilled and responsibilities unassigned.
In the past, our UI team had been, effectively, imaginary. Very few UI decisions were made, fewer were documented, and zero UI mockups were produced. So, during development, software engineers had no designs to engineer from so their work yielded emaciated and improvised results. I was not a big fan of this. During that semester, I tried to improve the system. I spoke to a manager, to the sect of individuals that responded when being addressed as the UI team, and the professors. However, I was not charismatic or tact, and, apparently, those qualities were needed of me for my success. So nothing was changed.
When the new semester started, I had the opportunity to group up with two other individuals and recreate the UI team. We did exactly that. So, over the past few weeks, we've been able to think through user interface requirements, and create mockups and designs that the engineers can refer to. Finally, we have nearly completed this task.
When the new UI team started, we tried to set some general goals to define the procedure of how we were going to work through the UI requirements and produced a design that engineers could use. One aspect of this was selecting a tool for producing user interface mockups. I looked at several that I discovered via of a few Google searches and web articles. Primarily, I was looking for something that was free and open source. But, I also was very keen on using a tool that was provided lots of control to allow speedy and precise production. Eventually, I settled on Pencil.
I found Pencil to be pretty satisfactory. It has a wide selection of objects to choose from, including GTK and Windows XP styled widgets. Pencil also provides ample control over how your configure the elements in your design. The interface allows you to specify exact pixel values for the size and position of objects. The appearance and style of objects can be tweaked in ways that are similar to how a webpage may be tweaked, where you can configure text styles, background colours, border colours, and the thickness and style - whether it is dashed or dotted or solid or whatever - on borders. Hotkeys are abundant in Pencil, so it is a suitable tool for those that really want to maximize their efficiency. It is available as an extension for Firefox and as a standalone application. Overall, it is a little quirky - and that works in its favour and against it - but I did find that it was intuitive and effective enough to be usable.
Also, I think I usually include some images relating to what I've been up too. So this is that. This image is a product of my attempts to come up with a bit of a mechanism to procedurally generate a glowing effect on objects. This was generated from an image of a pot. This image really doesn't reflect what I've been trying to achieve, but it does look pretty spiffy, so I saved it.