AAA Gamedev with Vim
I’ve been experimenting on and off with using Vim to write code at work, instead of Visual Studio, and recently I feel like I’ve reached a good enough spot to use it on a daily basis… here it is in action:
Keep reading if you want to know more!
Overview
Here’s the basic setup:
- CtrlP
- my fork of CtrlP Py Matcher
- Gutentags with either
Exhuberant Ctags or Universal
Ctags - p44vim
- YouCompleteMe with
clang
support - Some custom plugin (called
fb.vim
) that ties this all together specifically for Frostbite games codebases.
Vim Plugins
Listing Files
I’m using CtrlP to list files. This is your usual “fast open” thing, where you hit a keyboard shortcut, it opens a list of files, filters it down as you type a “fuzzy” pattern, and then gets out of your way. That’s what you see in the beginning of the video.
CtrlP requires a “root marker” to know what the root of a project is. However, Frostbite games have a lot of crap mixed up with all the source code – configuration scripts, tons of utilities, 3rd party libraries, etc. So asking CtrlP to index all of that would be madness.
The fb.vim
plugin therefore generates a “lister script” that lists all the actual source files I care about – engine code, game code, etc. – and I feed that script as CtrlP’s ctrlp_user_command
.
Note: Watch out, CtrlP requires passing the project root to user commands, even if you don’t need it because it’s already in some environment variables or something… so always add %s
somewhere in ctrlp_user_command
, otherwise you’ll get some completely silent errors that will leave you scratching your head for a while.
Pro tip: on Windows, you want to pass /-n /b /s /a-d
to dir
in order to get some nice output CtrlP can use.
Now you might be asking why I have a plugin generate the script, when I could have written the script directly by hand. Well if I was on a game team, working on the same codebase for 3 years, yeah maybe. But since I’m on the engine team, I have to juggle between dozens of branches, and dozens of different games – so I need the script to be portable, and generating it on Vim startup (when I detect the right environment) is the best way to keep that script up to date with my latest changes.
CtrlP Py-Matcher
Now the problem is performance. Even though I’m only interested in a subset of the codebase, that subset still has around 50k files in it… that’s where CtrlP Py-Matcher comes in.
The default search algorithm for CtrlP is implemented in VimScript so it’s, by definition, as portable as Vim, without the need to install anything. But it’s slow, whereas Py-Matcher is fast, but it’s implemented in Python so you need Python installed… but hey, good news, Python is installed anyways in a Frostbite environment! So yeah, that’s why I’m using that.
There are faster matchers out there for CtrlP (implemented in C/C++) but Windows binaries are hard to find, and Py-Matcher is good enough for this amount of files. Except that it had some Unix-isms that didn’t work well on Windows, so that’s why you may need my fork until my pull request is merged into the main project.
Tags
Ok now I can open files, but I can’t navigate the source code. Typically you need some kind of symbol database, which is where ctags
comes in – either Universal or Exhuberant, pick your poison (see links above).
Gutentags (by yours truly) manages the tags file for you, so just install it and be happy. However, it also needs to be told what the root of the project is and, just like with CtrlP, indexing the entirety of the
root folder of a AAA game’s repository would be madness. So the fb.vim
plugin (again) generates a “lister script” that will list the same files as for CtrlP, but for Gutentags.
Performance-wise, the resulting tags file contains around a million symbol definitions, and if I need to arbitarily jump to any of those through CtrlP, CtrlP Py-Matcher will take a second but will get there. Not super fast, but interactive enough.
So now I can navigate to any arbitrary tag, from anywhere. Yay!
Perforce
I can open files quickly, and navigate the source. But when I start typing, I need to potentially open that file for editing in Perforce, which is the source control management software that virtually all big game studios use. Unlike cool things like Mercurial or Git, all files in your repository are typically read-only until you explicitely check them out.
Fear not! Here comes P44Vim (by yours truly again), which is a super bare bones plugin for basic Perforce integration. It’s got only a couple commands, and automatically opens read-only file for edit when you start typing.
You don’t really see this part in the video since it happens behind the scenes.
Code Completion
Last but not least, I start typing some code, but there’s no code-completion! Usually I would go: “oh I need to give Intellisense another 10min before it wakes up”… but then I realize I’m not in Visual Studio anymore.
The biggest player in town for this is YouCompleteMe, which uses clang behind the scenes to compile stuff on the fly and give you almost-real-time feedback and completions. I was a bit frightened at first but they really tidied up their install procedure since last time I looked at it many years ago, and their
support for Windows seems pretty good. It only took me a couple minutes to get it going.
…except that, of course, we need to tell it how to compile our code. Once again, that’s where the fb.vim
plugin comes in. It will go lurk inside the Visual Studio solutions and extract everything YCM and clang need to know – include directories, preprocessor defines, etc. – about the current file.
All of this happens behind the scenes, but that’s how you see the code completion when I call a method on the data
variable, and how, when I later add an incorrect parameter to the function, it gives me feedback right away that this is wrong.
This has some issues, however. Our Windows build is not suposed to be compiled with clang, so I get a lot of warnings, along with a few errors, in the low level code (pragmas, attributes, SSE, etc.). I can pass the right flags to ignore the warnings (a whole bunch of -Wno-foobar
), but not the errors. But that’s OK, since clang still builds a mostly correct AST for my current file’s compilation unit, and I still get mostly correct code completion and hints. It’s not perfect, but it’s already better than Intellisense, and faster/lighter than Visual Assist.
Future Work
It’s getting pretty cozy in Vim, here, but there are still a few things to do:
- Setup OmniSharp: I configured YouCompleteMe to give me all the goodness I need in C++, but haven’t looked into it for C# stuff yet.
- Invalid characters in our code: There are quite a lot of files with a UTF BOM header for some reason, and, more puzzling, a few with just invalid UTF8 characters in them. This makes python serialization very upset when Vim passes the tags file to CtrlP Py-Matcher, so I currently have a hacky post-process setup in Gutentags that filters out any symbol with such invalid characters.
- Debugging: I don’t think there’s any getting around Visual Studio for this, and I don’t think anybody would want to anyway since Visual Studio’s debugger is still the best around (don’t get me started on gcc), but I would like to experiment with running an empty Visual Studio (without the whole, super heavy, solution loaded) directly from Vim, with some commands to tell it to open the same file as I have in Vim so I can add breakpoints.
That’s All Folks
If you have feedback, suggestions, or comments about how much of an old bearded nerd I am, please share!