Things have finally slowed down enough to get back into my passion, so here I am. What have I been up to?
Well, the game is getting complex to the point that just building with Visual Studio doesn’t cut it anymore. With over 15 projects in 3 different languages (and so different VS versions) and various interdependencies, builds were slowly getting screwed up. So I decided to switch to using MSBuild manually. Now I have complete control over how everything gets built, and the power to build the entire toolchain in a single command. Huh, toolchain? Oh…
Way back when, the game’s editor was built into the game itself. Eventually this became bothersome when expanding on the game’s features, so I looked into ways to separate the two. I had a lot of goals for the editor to cover many different areas (scripting, shader editing, level editing) and I didn’t want to make some gigantic super editor with a complex interface. I wanted to make a bunch of simpler editors that were designed to do one thing well. I also wanted all of the editors to be able to modify the game during runtime. So the problem became, how do you get a bunch of programs to talk to eachother?
I looked a few options for IPC: named pipes, shared memory, sockets. I eventually decided on named pipes via WCF. Named pipes wins on performance and ease of use. WCF makes it really easy to setup communication between multiple different programs. The way its setup is there’s a program that hosts the WCF service, then all editors/tools and the game itself connect to that host and talk to each other through the host.
Instead of using WCF’s serialization, I decided to use protocol buffers via protobuf-net (http://code.google.com/p/protobuf-net/). Protobuf-net is a great little library by Marc Gravell, a little light on documentation but then what isn’t these days. Now, everything works well if you treat F# as a syntax-light sort of functional C#, but if you embrace the language for its merits and and use things like discriminated unions (DU) or immutable objects, things get less nice. They way to get everything working is to make surrogates for your DUs. For DUs that don’t hold any values its pretty simple, one surrogate type can represent every valueless DU that you come up with. But for valued-DUs, you basically have to write a surrogate for each union, which contains a field for every possible value. I haven’t found a better way around this. In addition, you have to write that surrogate in C#, you can’t do it in F#. This is because discriminated unions in .Net are represented as a hierarchy of classes – but F# treats it all as one type. So for the following:
type Events =
| Foo of int
| Bar of int * int
There would be a class for Events, a class for Foo, and a class for Bar. Why is this important? Well, protobuf-net wants an exact conversion function from a type to its surrogate and back, and it sees any values of Foo as an instance of the Foo class, not Events. So you have to write a surrogate like:
type Surrogate() =
static member op_Implicit(surrogate : Surrogate) =
//extract the value from the surrogate and copy it
static member op_Implicit(value : Foo) =
//wrap the value in a surrogate
But you can’t say the type of value is Foo, because Foo isn’t a type to F#! The only exposed type is Events, and if you say value : Events, then protobuf-net will complain that there is no conversion operator for every case that it runs into (Foo, Bar). So, that has to be in C#, since it can see all of the types.
So with that said, now I can spend time working on a few editors so that testing and developing new game features becomes quick and easy. For now I’ll be working on an actor editor (for developing my component based design), shader editor (for work on graphics stuff), scripting editor (for my own language), and continue working on my game.