Maybe you don't know what I'm talking about - that's okay because the New Yorker published a feature on us this week for their tech issue:
GameDev.net and CRC Press have teamed up to bring a free ebook of content curated from top titles published by CRC Press. The freebook, Practices of Game Design & Indie Game Marketing, includes chapters from The Art of Game Design: A Book of Lenses, A Practical Guide to Indie Game Marketing, and An Architectural Approach to Level Design. The GameDev.net FreeBook is relevant to game designers, developers, and those interested in learning more about the challenges in game development. We know game development can be a tough discipline and business, so we picked several chapters from CRC Press titles that we thought would be of interest to you, the GameDev.net audience, in your journey to design, develop, and market your next game. The free ebook is available through CRC Press by clicking here. The Curated Books The Art of Game Design: A Book of Lenses, Second Edition, by Jesse Schell Presents 100+ sets of questions, or different lenses, for viewing a game’s design, encompassing diverse fields such as psychology, architecture, music, film, software engineering, theme park design, mathematics, anthropology, and more. Written by one of the world's top game designers, this book describes the deepest and most fundamental principles of game design, demonstrating how tactics used in board, card, and athletic games also work in video games. It provides practical instruction on creating world-class games that will be played again and again. View it here. A Practical Guide to Indie Game Marketing, by Joel Dreskin Marketing is an essential but too frequently overlooked or minimized component of the release plan for indie games. A Practical Guide to Indie Game Marketing provides you with the tools needed to build visibility and sell your indie games. With special focus on those developers with small budgets and limited staff and resources, this book is packed with tangible recommendations and techniques that you can put to use immediately. As a seasoned professional of the indie game arena, author Joel Dreskin gives you insight into practical, real-world experiences of marketing numerous successful games and also provides stories of the failures. View it here. An Architectural Approach to Level Design This is one of the first books to integrate architectural and spatial design theory with the field of level design. The book presents architectural techniques and theories for level designers to use in their own work. It connects architecture and level design in different ways that address the practical elements of how designers construct space and the experiential elements of how and why humans interact with this space. Throughout the text, readers learn skills for spatial layout, evoking emotion through gamespaces, and creating better levels through architectural theory. View it here. Learn more and download the ebook by clicking here. Did you know? GameDev.net and CRC Press also recently teamed up to bring GDNet+ Members up to a 20% discount on all CRC Press books. Learn more about this and other benefits here.
About this blog
We're pushing .NET technology to its limits. Come watch!
Entries in this blog
Maybe you don't know what I'm talking about - that's okay because the New Yorker published a feature on us this week for their tech issue:
Can Video Games Help Stroke Victims?
In the meantime, I happened to put together a video showing a prototype of the game, running off Kinect control. I thought you all might find it interesting, as it's a somewhat different control than the touch screen. Personally I think it's the best version of the experience we've made, and we've had several (touch screen, mouse, PS Move, Leap, etc). Unlike the touch screen version, you get full 3D directional control. We don't have to infer your motion intention. This makes a big difference in the feeling of total immersion.
For those of you who may not have followed my career path over time: A close friend and I have spent quite a few years doing R&D with purely physically driven animation. There's plenty of work out there on the subject; ours is not based on any of it and takes a completely different approach. About three years ago, we met a neurologist at the Johns Hopkins Hospital who helped us set up a small research group at Hopkins to study biological motion and create a completely new simulation system from the ground up, based around neurological principles and hands-on study of dolphins at the National Aquarium in Baltimore. Unlike many other physical animation systems, including our own previous work, the new work allows the physical simulation to be controlled as a player character. We also developed a new custom in-house framework, called the Kata Engine, to make the simulation work possible.
One of the goals in developing this controllable simulation was to learn more about human motor control, and specifically to investigate how to apply this technology to recovery from motor impairments such as stroke. National Geographic was kind enough to write some great articles on our motivations and approach:
Virtual Dolphin On A Mission
John Krakauer's Stroke of Genius
Although the primary application of our work is medical and scientific, we've also spent our spare time to create a game company, Max And Haley LLC, and a purely entertainment focused version of the game. This is the version that will be publicly available in a scant few days.
Here is a review of the game by AppUnwrapper.[quote]
I got my hands on the beta version of the game, and it's incredibly impressive and addictive. I spent two hours playing right off the bat without even realizing it, and have put in quite a few more hours since. I just keep wanting to come back to it. iPhones and iPads are the perfect platform for the game, because they allow for close and personal, tactile controls via simple swipes across the screen.[/quote]
I now have three shipped titles to my name; I'd say this is the first one I'm really personally proud of. It's my firm belief that we've created something that is completely unique in the gaming world, without being a gimmick. Every creature is a complete physical simulation. The dolphins you control respond to your swipes, not by playing pre-computed animation sequences but by actually incorporating your inputs into the drive parameters of the underlying simulation. The end result is a game that represents actual motion control, not gesture-recognition based selection of pre-existing motions.
As I said at the beginning of the post, this is mostly a promotional announcement. However, this is meant to be a technical blog, not my promotional mouthpiece. I want to dig in a lot to the actual development and technical aspects of this game. There's a lot to talk about in the course of developing a game with a three person (2x coder, 1x artist) team, building a complete cross-platform engine from nothing, all in the backdrop of an academic research hospital environment. Then there's the actual development of the simulation, which included a lot of interaction with the dolphins, the trainers, and the Aquarium staff. We did a lot of filming (but no motion capture!) in the course of the development as well; I'm hoping to share some of that footage moving forward.
Here's a slightly older trailer - excuse the wrong launch date on this version. We decided to slip the release by two months after this was created - that's worth a story in itself. It is not fully representative of the final product, but our final media isn't quite ready. Note that everything you see in the trailer is real gameplay footage on the iPad. Every last fish, shark, and cetacean is a physical simulation with full AI.
The seminal work driving this effort is really the findings by Daphne Bevalier at the University of Rochester. All of the papers are available for download as PDF, if you are so inclined. I imagine some background in psychology, cognitive science, neurology is helpful to follow everything that's going on. The basic take-away, though, is that video games can have dramatic and long-lasting positive effects on our cognitive and perceptual abilities. Here's an NPR article that is probably more helpful to follow as a lay-person with no background. One highlight:
[quote]Bavelier recruited non-gamers and trained them for a few weeks to play action video games. [...] Bavelier found that their vision remained improved, even without further practice on action video games. "We looked at the effect of playing action games on this visual skill of contrast sensitivity, and we've seen effects that last up to two years."[/quote]
Another rather interesting bit:
[quote]Brain researcher Jay Pratt, professor of psychology at the University of Toronto, has studied the differences between men and women in their ability to mentally manipulate 3-D figures. This skill is called spatial cognition, and it's an essential mental skill for math and engineering. Typically, Pratt says, women test significantly worse than men on tests of spatial cognition.
But Pratt found in his studies that when women who'd had little gaming experience were trained on action video games, the gender difference nearly disappeared.[/quote]
As it happens, I've wound up involved in this field as well. I had the good fortune to meet a doctor at the Johns Hopkins medical center/hospital who is interested in doing similar research. The existing work in the field is largely focused on cognition and perception; we'll be studying motor skills. Probably lots of work with iPads, Kinect, Wii, PS Move, and maybe more exotic control devices as well. There's a lot of potential applications, but one early angle will be helping stroke patients to recover basic motor ability more quickly and more permanently.
There's an added component as to why we're doing this research. My team believes that by studying the underlying neurology and psychology that drives (and is driven by) video games, we can actually turn the research around and use it to produce games that are more engaging, more interactive, more addictive, and just more fun. That's our big gambit, and if it pans out we'll be able to apply a more scientific and precise eye to the largely intuitive problem of making a good game. Of course the research is important for it's own sake and will hopefully lead to a lot of good results, but I went into games and not neurology for a reason ;)
I've been quiet for a very long time now, and this is why. We've just shipped our new game, Slug Bugs!
It uses our Ghost binaural audio which I've teased several times in the past, and is also wicked fun to play. Please check it out! A little later in the week I'll probably discuss the development more.
SVN is a long time stalwart as version control systems go, created to patch up the idiocies of CVS. It's a mature, well understood system that has been and continues to be used in a vast variety of production projects, open and closed source, across widely divergent team sizes and workflows. Nevermind the hyperbole, SVN is good by practically any real world measure. And like any real world production system, it has a lot of flaws in nearly every respect. A perfect product is a product no one uses, after all. It's important to understand what the flaws are, and in particular I want to discuss them without advocating for any alternative. I don't want to compare to git or explain why it fixes the problems, because that has the effect of lensing the actual problems and additionally the problem of implying that distributed version control is the solution. It can be a solution, but the problems reach a bit beyond that.
Committing vs publishing
Fundamentally, a commit creates a revision, and a revision is something we want as part of the permanent record of a file. However, a lot of those revisions are not really meant for public consumption. When I'm working on something complex, there are a lot of points where I want to freeze frame without actually telling the world about my work. Subversion understands this perfectly well, and the mechanism for doing so is branches. The caveat is that this always requires server round-trips, which is okay as long as you're in a high availability environment with a fast server. This is fine as long as you're in the office, but it fails the moment you're traveling or your connection to the server fails for whatever reason. Subversion cannot queue up revisions locally. It has exactly two reference points: the revision you started with and the working copy.
In general though, we are working on high availability environments and making a round trip to the server is not a big deal. Private branches are supposed to be the solution to this problem of work-in-progress revisions. Do everything you need, with as many revisions as you want, and then merge to trunk. Simple as that! If only merges actually worked.
SVN merges are broken
Yes, they're broken. Everybody knows merges are broken in Subversion and that they work great in distributed systems. What tends to happen is people gloss over why they're broken. There are essentially two problems in merges: the actual merge process, and the metadata about the merge. Neither works in SVN. The fatal mistake in the merge process is one I didn't fully understand until reading HgInit (several times). Subversion's world revolves around revisions, which are snapshots of the whole project. Merges basically take diffs from the common root and smash the results together. But the merged files didn't magically drop from the sky -- we made a whole series of changes to get them where they are. There's a lot of contextual information in those changes which SVN has completely and utterly forgotten. Not only that, but the new revision it spits out necessarily has to jam a potentially complicated history into a property field, and naturally it doesn't work.
For added impact, this context problem shows up without branches if two people happen to make more than trivial unrelated changes to the same trunk file. So not only does the branch approach not work, you get hit by the same bug even if you eschew it entirely! And invariably the reason this shows up is because you don't want to make small changes to trunk. Damned if you do, damned if you don't.
Newer version control systems are typically designed around changes rather than revisions. (Critically, this has nothing at all to do with decentralization.) By defining a particular 'version' of a file as a directed graph of changes resulting in a particular result, there's a ton of context about where things came from and how they got there. Unfortunately the complex history tends to make assignment of revision numbers complicated (and in fact impossible in distributed systems), so you are no longer able to point people to r3359 for their bug fix. Instead it's a graph node, probably assigned some arcane unique identifier like a GUID or hash.
File system headaches
.svn. This stupid little folder is the cause of so many headaches. Essentially it contains all of the metadata from the repository about whatever you synced, including the undamaged versions of files. But if you forget to copy it (because it's hidden), Subversion suddenly forgets all about what you were doing. You just lost its tracking information, after all. Now you get to do a clean update and a hand merge. Overwrite it by accident, and now Subversion will get confused. And here's the one that gets me every time with externals like boost -- copy folders from a different repository, and all of a sudden Subversion sees folders from something else entirely and will refuse to touch them at all until you go through and nuke the folders by hand. Nope, you were supposed to SVN export it, nevermind that the offending files are marked hidden.
And of course because there's no understanding of the native file system, move/copy/delete operations are all deeply confusing to Subversion unless it's the one who handles those changes. If you're working with an IDE that isn't integrated into source control, you have another headache coming because IDEs are usually built for rearranging files. (In fact I think this is probably the only good reason to install IDE integration.)
It's not clear to me if there's any productive way to handle this particular issue, especially cross platform. I can imagine a particular set of rules -- copying or moving files within a working copy does the same to the version control, moving them out is equivalent to delete. (What happens if they come back?) This tends to suggest integration at the filesystem layer, and our best bet for that is probably a FUSE implementation for the client. FUSE isn't available on Windows, though apparently a similar tool called Dokan is. Its maturity level is unclear.
Changelists are missing
Okay, this one is straight out of Perforce. There's a client side and a server side to this, and I actually have the client side via my favorite client SmartSVN. The idea on the client is that you group changed files together into changelists, and send them off all at once. It's basically a queued commit you can use to stage. Perforce adds a server side, where pending changelists actually exist on the server, you can see what people are working on (and a description of what they're doing!), and so forth. Subversion has no idea of anything except when files are different from their copies living in the .svn shadow directory, and that's only on the client. If you have a couple different live streams of work, separating them out is a bit of a hassle. Branches are no solution at all, since it isn't always clear upfront what goes in which branch. Changelists are much more flexible.
Locking is useless
The point of a lock in version control systems is to signal that it's not safe to change a file. The most common use is for binary files that can't be merged, but there are other useful situations too. Here's the catch: Subversion checks locks when you attempt to commit. That's how it has to work. In other words, by the time you find out there's a lock on a file, you've already gone and started working on it, unless you obsessively check repository status for files. There's also no way to know if you're putting a lock on a file somebody has pending edits to.
The long and short of it is if you're going to use a server, really use it. Perforce does. There's no need to have the drawbacks of both centralized and distributed systems at once.
I think that's everything that bothers me about Subversion. What about you?
Last time I talked about Mercurial, and was generally disappointed with it. I also evaluated Git, another major distributed version control system (DVCS).
Short Review: Quirky, but a promising winner.
Git, like Mercurial, was spawned as a result of the Linux-BitKeeper feud. It was written initially by Linus Torvalds, apparently during quite a lull in Linux development. It is for obvious reasons a very Linux focused tool, and I'd heard that performance is poor on Windows. I was not optimistic about it being usable on Windows.
Installation actually went very smoothly. Git for Windows is basically powered by MSYS, the same Unix tools port that accompanies the Windows GCC port called MinGW. The installer is neat and sets up everything for you. It even offers a set of shell extensions that provide a graphical interface. Note that I opted not to install this interface, and I have no idea what it's like. A friend tells me it's awful.
Once the installer is done, git is ready to go. It's added to PATH and you can start cloning things right off the bat. Command line usage is simple and straightforward, and there's even a 'config' option that lets you set things up nicely without having to figure out what config file you want and where it lives. It's still a bit annoying, but I like it a lot better than Mercurial. I've heard some people complain about git being composed of dozens of binaries, but I haven't seen this on either my Windows or Linux boxes. I suspect this is a complaint about old versions, where each git command was its own binary (git-commit, git-clone, git-svn, etc), but that's long since been retired. Most of the installed binaries are just the MSYS ports of core Unix programs like ls.
I was also thrilled with the git-svn integration. Unlike Mercurial, the support is built in and flat out works with no drama whatsoever. I didn't try committing back into the Subversion repository from git, but apparently there is fabulous two way support. It was simple enough to create a git repository but it can be time consuming, since git replays every single check-in from Subversion to itself. I tested on a small repository with only about 120 revisions, which took maybe two minutes.
This is where I have to admit I have another motive for choosing Git. My favorite VCS frontend comes in a version called SmartGit. It's a stand-alone (not shell integrated) client that is free for non commercial use and works really well. It even handled SSH beautifully, which I'm thankful about. It's still beta technically, but I haven't noticed any problems.
Now the rough stuff. I already mentioned that Git for Windows comes with a GUI that is apparently not good. What I discovered is that getting git to authenticate from Windows is fairly awful. In Subversion, you actually configure users and passwords explicitly in a plain-text file. Git doesn't support anything of the sort; their 'git-daemon' server allows fully anonymous pulls and can be configured for anonymous-push only. Authentication is entirely dependent on the filesystem permissions and the users configured on the server (barring workarounds), which means that most of the time, authenticated Git transactions happen inside SSH sessions. If you want to do something else, it's complicated at best. Oh, and good luck with HTTP integration if you chose a web server other than Apache. I have to imagine running a Windows based git server is difficult.
Let me tell you about SSH on Windows. It can be unpleasant. Most people use PuTTY (which is very nice), and if you use a server with public key authentication, you'll end up using a program called Pageant that provides that service to various applications. Pageant doesn't use OpenSSH compatible keys, so you have to convert the keys over, and watch out because the current stable version of Pageant won't do RSA keys. Git in turn depends on a third program called Plink, which exists to help programs talk to Pageant, and it finds that program via the GIT_SSH environment variable. The long and short of it is that getting Git to log into a public key auth SSH server is quite painful. I discovered that SmartGit simply reads OpenSSH keys and connects without any complications, so I rely on it for transactions with our main server.
I am planning to transition over to git soon, because I think that the workflow of a DVCS is better overall. It's really clear, though, that these are raw tools compared to the much more established and stable Subversion. It's also a little more complicated to understand; whether you're using git, Mercurial, or something else it's valuable to read the free ebooks that explain how to work with them. There are all kinds of quirks in these tools. Git, for example, uses a 'staging area' that clones your files for commit, and if you're not careful you can wind up committing older versions of your files than what's on disk. I don't know why -- seems like the opposite extreme from Mercurial.
It's because of these types of issues that I favor choosing the version control system with the most momentum behind it. Git and Mercurial aren't the only two DVCS out there; Bazaar, monotone, and many more are available. But these tools already have rough (and sharp!) edges, and by sticking to the popular ones you are likely to get the most community support. Both Git and Mercurial have full blown books dedicated to them that are available electronically for free. My advice is that you read them.
I've been a long time Subversion user, and I'm very comfortable with its quirks and limitations. It's an example of a centralized version control system (CVCS), which is very easy to understand. However, there's been a lot of talk lately about distributed version control systems (DVCS), of which there are two well known examples: git and Mercurial. I've spent a moderate amount of time evaluating both, and I decided to post my thoughts. This entry is about Mercurial.
Short review: A half baked, annoying system.
I started with Mercurial, because I'd heard anecdotally that it's more Windows friendly and generally nicer to work with than git. I was additionally spurred by reading the first chapter of HgInit, an e-book by Joel Spolsky of 'Joel on Software' fame. Say what you will about Joel -- it's a concise and coherent explanation of why distributed version control is, in a general sense, preferable to centralized. Armed with that knowledge, I began looking at what's involved in transitioning from Subversion to Mercurial.
Installation was smooth. Mercurial's site has a Windows installer ready to go that sets everything up beautifully. Configuration, however, was unpleasant. The Mercurial guide starts with this as your very first step:
As first step, you should teach Mercurial your name. For that you open the file ~/.hgrc with a text-editor and add the ui section (user interaction) with your username:
Yes, because what I've always wanted from my VCS is for it to be a hassle every time I move to a new machine. Setting up extensions is similarly a pain in the neck. More on that in a moment. Basically Mercurial's configurations are a headache.
Then there's the actual VCS. You see, I have one gigantic problem with Mercurial, and it's summed up by Joel:
Whereas, in Mercurial, all commands always apply to the entire tree. If your code is in c:\code, when you issue the hg commit command, you can be in c:\code or in any subdirectory and it has the same effect.This is an incredibly awkward design decision. The basic idea, I guess, is that somebody got really frustrated about forgetting to check in changes and decided this was the solution. My take is that this is a stupid restriction that makes development unpleasant.
When I'm working on something, I usually have several related projects in a repository. (Mercurial fans freely admit this is a bad way to work with it.) Within each project, I usually wind up making a few sets of parallel changes. These changes are independent and shouldn't be part of the same check-in. The idea with Mercurial is, I think, that you simply produce new branches every time you do something like this, and then merge back together. Should be no problem, since branching is such a trivial operation in Mercurial.
So now I have to stop and think about whether I should be branching every time I make a tweak somewhere?
Oh but wait, how about the extension mechanism? I should be able to patch in whatever behavior I need, and surely this is something that bothers other people! As it turns out that definitely the case. Apart from the branching suggestions, there's not one but half a dozen extensions to handle this problem, all of which have their own quirks and pretty much all of which involve jumping back into the VCS frequently. This is apparently a problem the Mercurial developers are still puzzling over.
Actually there is one tool that's solved this the way you would expect: TortoiseHg. Which is great, save two problems. Number one, I want my VCS features to be available from the command line and front-end both. Two, I really dislike Tortoise. Alternative Mercurial frontends are both trash, and an unbelievable pain to set up. If you're working with Mercurial, TortoiseHg and command line are really your only sane options.
It comes down to one thing: workflow. With Mercurial, I have to be constantly conscious about whether I'm in the right branch, doing the right thing. Should I be shelving these changes? Do they go together or not? How many branches should I maintain privately? Ugh.
Apart from all that, I ran into one serious show stopper. Part of this test includes migrating my existing Subversion repository, and Mercurial includes a convenient extension for it. Wait, did I say convenient? I meant borderline functional:
Subversion's Python bindings are a prerequisite. The bindings (generated with SWIG) are installed separately on Windows, and can be found on http://subversion.tigris.org/ . Note that you can't do this with the Win32 Mercurial binaries -- there's no way to install the Subversion bindings into its built-in Python library. So you'll need to use a Mercurial installed on top of a stand-alone Python, and you may also need to do something like "set HG=python c:\Python25\Scripts\hg" to override the default Win32 binaries if you have those installed also. For Mac OS X, the easiest way is to install the CollabNet Subversion build, and then copy the content of /opt/subversion/lib/svn-python to the site-package directory of the python installation.
The silver lining is there are apparently third party tools to handle this that are far better, but at this point Mercurial has tallied up a lot of irritations and I'm ready to move on.
Spoiler: I'm transitioning to git. I'll go into all the gory details in my next post, but I found git to be vastly better to work with.
Vimeo link (looks nicer)
Also can't help but notice that YouTube HD's encode quality is awful.
My last tech post was heavily negative, so today I'm going to try and be more positive. I've been working with a library called NHibernate, which is itself a port of a Java library called Hibernate. These are very mature, long-standing object relational mapping systems that I've started exploring lately.
Let's recap. Most high end storage requirements, and nearly all web site storage, are handled using relational database management systems, RDBMS for short. These things were developed starting in 1970, along with the now ubiquitous SQL language for working with them. The main SQL standard was laid down in 1992, though most vendors provide various extensions for their specific systems. Ignoring some recent developments, SQL is the gold standard for handling relational database systems.
When I set out to build SlimTune, one of the ideas I had was to eschew the fairly crude approach that most performance tools take with storage and build it around a fully relational database. I bet that I could make it work fast enough to be usable for profiling, and simultaneously more expressive and flexible. The ability to view the profile live as it evolves is derived directly from this design choice. Generally speaking I'm really happy with how it turned out, but there was one mistake I didn't understand at the time.
SQL is garbage. (Damnit, I'm being negative again.)
I am not bad at SQL, I don't think. I know for certain that I am not good at SQL, but I can write reasonably complex queries and I'm fairly well versed in the theory behind relational databases. The disturbing part is that SQL is very inconsistent across database systems. The standard is missing a lot of useful functionality -- string concatenation, result pagination, etc -- and when you're using embedded databases like SQLite or SQL Server Compact, various pieces of the language are just plain missing. Databases also have more subtle expectations about what operations may or may not be allowed, how joins are set up, and even syntactical details about how to refer to tables and so on.
SQL is immensely powerful if you can choose to only support a limited subset of database engines, or if your query needs are relatively simple. Tune started running into problems almost immediately. The visualizers in the released version are using a very careful balance of the SQL subset that works just so on the two embedded engines that are in there. It's not really a livable development model, especially as the number of visualizers and database engines increases. I needed something that would let me handle databases in a more implementation-agnostic way.
After some research it became clear that what I needed was an object/relational mapper, or ORM. Now an ORM does not exist to make databases consistently; that's mostly a side effect of what they actually do, which is to hide the database system entirely. ORMs are actually the most popular form of persistence layers. A persistence layer exists to allow you to convert "transient" data living in your code to "persistent" data living in a data store, and back again. Most code is object oriented and most data stores are relational, hence the popularity of object/relational mapping.
After some reading, I picked NHibernate as my ORM of choice, augmented by Fluent mapping to get away from the XML mess that NH normally uses. It's gone really well so far, but over the course of all this I've learned it's very important to understand one thing about persistence frameworks. They are not particularly generalized tools, by design. Every framework, NH included, has very specific ideas about how the world ought to work. They tend to offer various degrees of customization, but you're expected to adhere to a specific model and straying too far from that model will result in pain.
Persistence frameworks are very simple and effective tools, but they sacrifice both performance and flexibility to do so. (Contrast to SQL, which is fast and flexible but a PITA to use.) Composite keys? Evil! Dynamic table names? No way! I found that NHibernate was amongst the best when it came to allowing me to bend the rules -- or flat out break them. Even so, Tune is a blend of NH and native database code, falling back to RDBMS-specific techniques in areas that are performance sensitive or outside of the ORM's world-view. For example, I use database specific SQL queries to clone tables for snapshots. That's not something you can do in NH because the table itself is an implementation detail. I also use database specific techniques to perform high-volume database work, as NH is explicitly meant for OLTP and not major bulk operations.
Despite all the quirks, I've been really pleased with NHibernate. It's solved some major design problems in a relatively straightforward fashion, despite the somewhat awkward learning curve and lots of bizarre problem solving due to my habit of using a relational database as a relational database. It provides a query language that is largely consistent across databases, and very effective tools for building queries dynamically without error-prone string processing. Most importantly, it makes writing visualizers for Tune and all around much smoother, and that means more features more quickly.
So yeah, I like NHibernate. That said, I also like this rant. Positive thinking!
I find Windows Installer to be truly baffling. It's as close to the heart of Windows as any developer tool gets. It is technology which literally every single Windows user interacts with, frequently. I believe practically every single team at Microsoft works with it, and that even major applications like Office, Visual Studio, and Windows Update are using it.
So I don't understand. Why is Installer such a poorly designed, difficult to use, and generally infuriating piece of software?
Let's recap on the subject of installers. An installer technology should facilitate two basic tasks. One, it should allow a developer to smoothly install their application onto any compatible system, exposing a UI that is consistent across every installation. Two, it should allow the user to completely reverse (almost) any installation at will, in a straightforward and again consistent fashion. Windows, Mac OSX, and Linux take three very different approaches to this problem, with OSX being almost indisputably the most sane. Linux is fairly psychotic under the hood, but the idea of a centralized package repository (almost like an "app store" of some kind) is fairly compelling and the dominant implementations are excellent.
And then we have Windows. The modern, recommended approach is to use MSI based setup files, which are basically embedded databases and show a mostly similar UI. And then there's InstallShield, NSIS, InnoSetup, and half a dozen other installer technologies that are all in common use. Do you know why that is? It's because Windows Installer is junk.
Let us start with the problem of consistency. This is our very nice, standard looking SlimDX SDK installation package:
And this is what it looks like if you use Visual Studio to create your installer:
Random mix of fonts? Check. Altered dialog proportions for no reason? Check. Inane question that makes no sense to most users? Epic check. Hilariously amateur looking default clip art? Of course.
Okay, so maybe you don't think the difference is that big. Microsoft was never Apple, after all. But how many of those childish looking VS based installers do you see on a regular basis? It's not very many. That's because the installer creation built into Visual Studio, Microsoft's premiere idol of the industry development tool, is utter garbage. Not only is the UI for it awful, it fails to expose most of the useful things MSI can actually do, or most developers want to do. Even the traditionally expected "visual" half-baked dialog editor never made it into the oven. You just get a series of bad templates with static properties. Microsoft also provides an MSI editor, which looks like this:
Wow! I've always wanted to build databases by hand from scratch. Why not just integrate the functionality into Access?
In fact, Microsoft is now using external tools to build installers. Office 2007's installer is written using the open source WiX toolset. Our installer is built using WiX too, and it's an unpleasant but workable experience. WiX essentially translates the database schema verbatim into an XML schema, and automates some of the details of generating unique IDs etc. It's pretty much the only decent tool for creating MSI files of any significant complexity, especially if buying InstallShield is just too embarrassing (or expensive, $600 up to $9500). By the way, Visual Studio 2010 now includes a license for InstallShield Limited Edition. I think that counts as giving up.
Even then, the thing is downright infuriating. You cannot tell it to copy the contents of a folder into an installer. There is literally no facility for doing so. You have to manually replicate the entire folder hierarchy, and every single file, interspersed with explicit uniquely identified Component blocks, all in XML. And all of those components have to be explicitly be referenced into Feature blocks. SlimDX now ships a self extracting 7-zip archive for the samples mainly because the complexity of the install script was unmanageable, and had to be rebuilt with the help of a half-baked C# tool each release.
Anyone with half a brain might observe at this point that copying a folder on your machine to a user's machine is mostly what an installer does. In terms of software design, it's the first god damned use case.
Even all of that might be okay if it weren't for one critical problem. Lots of decent software systems have no competent toolset. Unfortunately it turns out that the underlying Windows Installer engine is also a piece of junk. The most obvious problem is its poor performance (I have an SSD, four cores, and eight gigabytes of RAM -- what is it doing for so long before installation starts?), but even that can be overlooked. I am talking about one absolutely catastrophic, completely unacceptable design flaw.
Windows Installer cannot handle dependencies.
Let that sink in. Copying a local folder to the user's system is use case number one. Setting up dependencies is, I'm pretty sure, the very next thing on the list. And Windows Installer cannot even begin to contemplate it. You expect your dependencies to be installed via MSI, because it's the standard installer system, and they usually are. Except...Windows Installer can't chain MSIs. It can't run one MSI as a child of another. It can't run one MSI after another. It sure can't conditionally install subcomponents in separate MSIs. Trying to run two MSI installs at once on a single system will fail. (Oh, and MS licensing doesn't even allow you to integrate any of their components directly in DLL form, the way OSX does. Dependencies are MSI or bust.)
The way to set up dependencies is to write your own custom bootstrap installer. Yes, Visual Studio can create the bootstrapper, assuming your dependencies are one of the scant few that are supported. However, we've already established that Visual Studio is an awful choice for any installer-related tasks. In this case, the bootstrapper will vomit out five mandatory files, instead of embedding them in setup.exe. That was fine when software was still on media, but it's ridiculous for web distribution.
Anyway, nearly any interesting software requires a bootstrapper, which has to be pretty much put together from scratch, and there's no guidelines or recommended approaches or anything of the sort. You're on your own. I've tried some of the bootstrap systems out there, and the best choice is actually any competing installer technology -- I use Inno. Yes, the best way to make Windows Installer workable is to actually wrap it in a third party installer. And I wonder how many bootstrappers correctly handle silent/unattended installations, network administrative installs, logging, UAC elevation, patches, repair installs, and all the other crazy stuff that can happen in installer world.
One more thing. The transition to 64 bit actually made everything worse. See, MSIs can be built as 32 bit or 64 bit, and of course 64 bit installers don't work on 32 bit systems. 32 bit installers are capable of installing 64 bit components though, and can be safely cordoned off to exclude those pieces when running on a 32 bit system. Except when they can't. I'm not sure exactly how many cases of this there are, but there's one glaring example -- the Visual C++ 2010 64 bit merge module. (A merge module is like a static library, but for installers.) It can't be included in a 32 bit installer, even though the VC++ 2008 module had no problem. The recommended approach is to build completely separate 32 and 64 bit installers.
Let me clarify the implications of that statement. Building two separate installers leaves two choices. One choice is to let the user pick the correct installation package. What percentage of Windows users do you think can even understand the selection they're supposed to make? It's not Linux, the people using the system don't know arcane details like what bit-size their OS installation is. (Which hasn't stopped developers from asking people to choose anyway.) That leaves you one other choice, which is to -- wait for it -- write a bootstrapper.
Alright, now I'm done. Despite all these problems, apparently developers everywhere just accept the status quo as perfectly normal and acceptable. Or maybe there's a "silent majority" not explaining to Microsoft that their entire installer technology, from top to bottom, is completely mind-fucked.
To a large extent, people's expectations do not align with what BioReplicants actually does. Our eventual goal is to meet those expectations, but in the meantime there is a very tricky problem of explaining what our system actually does for them. I think that will continue to be a problem, exacerbated by the fact that on the surface, we seem to be competing with NaturalMotion's Euphoria product, and in fact we've encouraged that misconception.
In truth, it's not the case. We aren't doing anything like what NM does internally, and all we're really doing is trying to solve the same problem every game has to solve. Everybody wants realistic, varied, complex, and reactive animations for their game. Everybody! And frankly, they don't need Euphoria or BioReplicants to do it. There's at least three GDC talks this year on the subject. That's why it's important to step back and look at why middleware even exists.
The rest of this post is at Ventspace. Probably one of my best posts in a long time, actually.
This is what we've been working on for the last several months at AR Labs.
BioReplicant keeps walking.
firstname.lastname@example.org for more information.
BioReplicants is a completely reactive procedural animation system for use in video games. No key framing, motion capture, or precomputed animations were used. Everything you see here was generated in real-time, reacting to human input. Oh, and it's efficient enough to run on an iPhone.
We know he looks crazy. Sure we could've made it realistic, but it's just not that interesting to watch. BioReplicant can keep going even through bone crushing impacts, and we think that's pretty cool.
We'll be showing off the LIVE DEMO at GDC. Catch up with us to try it out!
I'm working on some final touches for SlimTune's next version, and one of them involves persisting the launcher settings between application runs. Launching is handled by an interface ILauncher, which can be set to any number of things via a reflected list of inherited types. A PropertyGrid is used to configure the settings, and all the underlying code ever sees is the interface. SlimTune's a plugin based C# app, and this is all pretty standard.
When it came to persisting this data across sessions, I figured it'd be no big deal -- I'll just serialize the object out to isolated storage, and deserialize it again when I need it. There's one hang-up, though. Serializers (or at least XmlSerializer) can't handle interfaces! Worse still, the so-called solutions I found online were utterly ludicrous. It turns out this is actually an incredibly easy problem to solve, and mainly involves stopping and thinking about what you're doing for about five seconds.
Alright, so we can't serialize an interface, but we can serialize any concrete type. Same goes for the deserialization process. The answer is to simple: store the concrete type with the serialized data.
//save the launcher configuration to isolated storage
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
using(var configFile = new IsolatedStorageFileStream(ConfigFile, FileMode.Create, FileAccess.Write, isoStore))
var launcherType = m_launcher.GetType();
//write the concrete type so we know what to deserialize
string launcherTypeName = launcherType.AssemblyQualifiedName;
var sw = new StreamWriter(configFile);
//write the object itself
var serializer = new XmlSerializer(launcherType);
We simply ask the interface to give us its real type, and record it to the file before serializing. Okay, so the result won't be a legal XML file, but how often is that actually a problem? Now the deserialize side of the equation:
//try and load a launcher configuration from isolated storage
var isoStore = IsolatedStorageFile.GetUserStoreForApplication();
using(var configFile = new IsolatedStorageFileStream(ConfigFile, FileMode.Open, FileAccess.Read, isoStore))
//read the concrete type to deserialize
var sr = new StreamReader(configFile);
var launcherTypeName = sr.ReadLine();
var launcherType = Type.GetType(launcherTypeName, true);
//read the actual object
XmlSerializer serializer = new XmlSerializer(launcherType);
m_launcher = (ILauncher) serializer.Deserialize(sr);
Reversing things, we first read the type that was written to file, and reconstruct the actual concrete type that goes with that string. Then we know exactly what to deserialize, and XmlSerializer is happy to oblige.
Now that wasn't so hard, was it?
ClickOnce has actually been on the to-do list for a very long time, but it ended up quite far down the priority list thanks to a lack of user demand. For the February 2010 release we've gone ahead and included it. The installer will set it up for VS 2008 and VS 2010; we've dropped 2005 support across the board so no ClickOnce there. There are a few quirks to setting it up properly though, so I just want to explain what you need to do in order to make sure it works properly.
First of all, make sure you've got a reference to the GAC version of SlimDX in your project (via the .NET tab in Add References). Also check the properties of the SlimDX reference; the default is Copy Local = True and that should be set to False.
Once you've done that, go into your project's properties and select the Publish tab. This is where you set up all of the ClickOnce options and actually produce a distribution. If you press Application Files, you should see SlimDX.dll listed as Prerequisite (Auto). If it's something else, you've got the previous step wrong.
Next, hit the Prerequisites... button. Somewhere in the listbox, you'll see "SlimDX Runtime (February 2010)". Check the box and press OK.
That's it. Pretty easy, huh? Now when you publish, the SlimDX runtime will be included with your application and run automatically as part of the ClickOnce installation.
I don't want to really push anyone into gutting a working system, though. If you can include a processor that would be great, because I'm not sure if the one I have works. 2 sticks of memory would be helpful too -- I've got two but why stop there?
Let me know if you guys have anything lying around.
Here's a quick teaser of the new UI:
The window hosting the visualizer is missing all of its widgets, but will eventually have a variety of controls along the edges. The revised main SlimTune window is essentially complete. This window is always open as long as SlimTune is running, and maintains a list of the connections that are active. One window, one connection, and closing one closes the other. It's much easier to keep track of things this way, and the individual windows can be hidden away to reduce clutter if desired.
Still working on the details, but here are some new teaser shots.
[Update] Slightly newer version of the visualizer:
The best part of the current iteration? NO DAMN REFRESH BUTTON! The graph redraws itself, and the counter list updates itself. No user interaction required.
I've now added service and ASP.NET profiling support to SlimTune. Services seem to work, although I've tested it pretty minimally. ASP.NET should work but I'm really not set up to test it properly. I might attempt a VM based test later, because I'm not really sure what sort of status IIS is on my main machine and I don't really want to find out. Still, ASP.NET is little more than a special case of the service profiling.
Unfortunately, it turns out that admin level privileges are required in order to control (and therefore profile) services. I've decided not to automatically request privilege escalation in SlimTune. Instead, it simply blocks you from selecting service or ASP.NET profiling unless you're running with administrator privileges (and pops up a message box explaining this). You'll have to right click -> Run as Administrator in order to select those options, unless you've turned off UAC outright. Kind of annoying, but I figured it was the best compromise.
Incidentally, the code to support this is mostly cloned out of CLRProfiler, with some work to integrate it into SlimTune smoothly. I don't even understand why half of it is there. You know why? It's because there's no other documentation about how to do it. This problem is somewhat endemic across all the .NET profiling bits, unfortunately. It may also affect the debugger documentation, but I'm not sure.
SlimTune is essentially patched together using a combination of a helpful CodeProject sample, the official documentation, blog posts, MSDN forum questions, and experimentation. I'm hopefully that by publishing a reasonably full featured open source profiler, I'm also creating a good practical reference on how to handle the guts of .NET. I've considered blogging more about the internals as well, but that remains to be seen.
[Update] I would like to mention, though, that this is vastly more documentation than is available for Mono.
Let's recap. Every other profiler I'm aware of works in more or less the same way. While the application is running, data is written to a file. Once the run is complete, the frontend steps in to parse the data and visualize it one way or another. SlimTune on the other hand allows (encourages, in fact) live visualization while the application is running. It also supports very different visualizations that slice the data in entirely different ways. The enabling technology for these features is the use of an embedded database. I'm not sure why no one else has taken this approach, but my theory at the time was that it was a simple matter of performance. Databases have to be manipulated with SQL, have to store everything in tables, etc. I suspected that updating a database so often was a problem. My goal was to write a blindingly fast database backend that would be capable of handling large amounts of data efficiently.
Read the rest of the post at Ventspace.
One of the ideas I had with SlimTune was to make the front-end pluggable, so that you or I could develop various views of the data that are neatly customized to focused goals, or provide cool new features. That has worked out fairly well, with the caveat that no one except me is writing visualizers. (That's fine, the database format isn't that stable yet.) However, there turned out to be a number of problems with how the views are actually managed.
Read the rest of the post on Ventspace.
One of the create flags for D3D 9 devices is FpuPreserve. It tells the Direct3D runtime that you don't want it to mess with the FPU flags, which it does to improve performance. And you should probably be using it.
FPU computations are a really hideously messy area, one that makes my head spin when you get into the details. One of the cool things .NET does is to take away most of the complexity and make very simple, straightforward guarantees about how floating point code must behave. Operations are done at specifically defined precision, in a certain way, and the runtime must enforce these requirements during code generation. (Which creates some weird x86 code.)
When DirectX goes in and messes with FPU state, it apparently throws off what .NET expects, leading to weird bugs of various sorts. So unless you've got some problem with FPU performance that can be solved by switching to the faster FPU states (hint: you don't), it's probably a good idea to simply set FpuPreserve all the time.
[EDIT] I forgot to mention as an addendum that as part of the SlimDX 2.0 transition, it's very likely this flag will become the default.
Read the rest of the post on Ventspace.
I'd like to introduce you all to our new company, Action = Reaction Labs LLC. Our goal is to bring a pair of new technologies to the games market, starting with the iPhone, that I think could really change things. I know that's a pretty ballsy statement, but stay tuned over the course of the next year at least, and a lot of interesting things should be happening. We're still working on a corporate site but I'll let you all know when that's ready.
AR Labs has two completely separate pieces of technology, both of which are hopefully going to make a big difference to gamers. Both technologies are shown off in a very early prototype form in our first iPhone game, Aves. There will be a second game later this year that will showcase far more advanced versions of both.
The first is our Ghost Dynamic Binaural Audio system. It's been known for a very long time that traditional 3D sound techniques are fairly flat and ineffective. There is something known as binaural recording which produces a much, much more realistic and convincing soundstage for listeners using headphones. Check out Jeff's Five Favorite Things for a demonstration. Until now, binaural audio has been restricted to statically positioned recordings, not suitable for games where things move dynamically. We've overcome this limitation, and can to produce sound that is dynamically positioned in true 3D, just like in Jeff's video. Best of all, the Ghost SDK is currently under development, and should be available to all iPod/iPhone developers within a few short months!
The second technology is the BioReplicants physical animation system. We're not the first to do physically based animation, by any stretch. Unlike a certain well known company however, our system is true middleware and will drop into existing games without requiring engineers on site to tune. Not only that, but our characters are truly capable of walking, running, jumping, flying, flipping, and so much more without an animator ever getting involved. They're also truly interactive -- shove one and it will readjust as necessary to restore its balance and desired animation in a convincing way. This isn't just some clever ragdoll based trick, and it's not just to watch "a different tackle every time". That's no better than pre-rendered cutscenes. You'll see what I mean over the coming months as we start to demo the current generation of our technology.
There's my sales pitch. This is quite literally MY company -- I am CTO and part owner. I'm hoping to talk a lot more about what we've got in the pipeline. Tech details are of course going to be scarce, but please don't hesitate to ask and I'll provide what information I can. I'm especially interested in speaking to iPod/iPhone developers, since that's going to be our first focus with the Ghost SDK. Nearly everybody playing those games is using headphones, making it the perfect platform for what we've got. And candidly, I'm planning to make it must-have technology for any serious iPod game.
sure stay in school for your deplomas, in my apionon unless you wanting to work for others its a complete wast of valuable time.
I'd like to provide some commentary, as someone who actually got a game industry job without a degree, and who just finished his degree.
As usual, the rest of the post is available on Ventspace. This way, I get to actually track statistics!