Archive for the ‘Uncategorized’ Category

All About Documentation

There is a recent article on Gamasutra: Game Dev Collaboration: Google Docs Style. Every developer has his own story about the failures of documentation. I would have hoped that those thinking about this the most have already moved past the ‘silver bullet’ naiveté Chris shows in that article (well, what do you expect from producers…), but apparently not. Which is sad, because the problem is a single concept with really only two solutions.

The problem is usability.

The solutions are resignation or intense investment.

No one wants to document because 1) It is a pain to document using any software or system, including Google Docs, and 2) It is even more painful to update documentation using any software or system, including Google Docs. When a virtual process is painful, there are always things we can do to make it less painful (and ideally, painless). Blah blah blah. The problem is obvious. The solutions are not.

Solution 1: Resignation. Don’t even attempt to document.

Obviously that is a bit of a generalization. Really, it means don’t force, standardize, or expect documentation. People will document things on their own, using the best ways available, when it becomes an obvious benefit. Ultimately, people are just asking each other for information, and remember that developers, like all humans, are incredibly lazy. How many times have you not bookmarked a document link someone sent you? How many times have you kept open an IM window because you don’t want to write the info down? This is natural. We are usually asking for help because we’re doing something unusual, outside of our day-to-day, and the truth is we don’t need this info that often. Documentation is not that useful when someone is learning something for the first time. It is more effective to learn from someone and the benefit of documentation is slight, especially when the documentation is not kept up to date.

All the wiki-cloud-collaborative-meta-web-editor software in the world isn’t going to change these facts. There is a barrier that even Google Docs, which I think is the easiest-to-use software for documentation available, cannot itself overcome.

So, like I was saying, doing nothing is probably fine, even for large projects. On small projects, communication is better. On large projects, things move much faster than the few foolhardy souls who are willing to document can keep up with. Things will get documented occasionally, and everyone will expect the inevitable, and who knows, maybe we’ll build our schedules to take this into account and we’ll build more intuitive systems, tools, and interfaces.

The one exception to this is for outsourcing, which I’ll touch on later, because the logic for an internal development team is inverted with outsourcers.

Solutions 2: Intense investment. Smart people make a serious effort.

The problem with documentation is that the systems for managing it haven’t achieved a high enough level of usability. The cause of that problem is, our best and brightest haven’t really worked on the problem. It doesn’t get respect. Which is strange, when you consider what we have figured out. We in games deal with a product that thrives on and is reliant on usability, and no one I know of, even those studios with awesome tools, have figured out documentation.

I don’t have an actual solution. I am working on one, and hopefully can implement it at BioWare, but it is just one possible solution and who knows if it’ll work. My point is that we don’t take it seriously. We don’t even think about it correctly. We treat it as a separate entity, but that treatment has failed us. It is a subset of tool design, the same way UI and menu design is. If you haven’t thought about documentation as a living component of your tool, your tool has poor usability, no matter how actually usable your application is. This ‘integrated documentation’ thinking is common in shrink-wrapped applications; just think of context-sensitive ‘F1′ that brings up help to the current word under the cursor in a code editor, or activity or menu generally. The added complexity in our industry comes with the fact that our tools and systems are constantly evolving and changing, and docs are almost always written and updated in spare unscheduled time by development team members- two complexities which generally do not exist for shrink-wrapped applications.

We need to start treating documentation as a first-class issue and component of our tools, no matter how bad our tools are. That doesn’t mean scheduling time, it doesn’t mean creating a documentation superstructure that sits on top of our actual tools, like wikis/google docs/word docs do. It means really, truly integrating documentation into design and implementation of tools, and having your best people work on the tech for it, and having all the documentation happen by the actual users (so hard-coded message boxes that display info are out).

Hopefully in a few weeks I should have some progress to show on my collaborative documentation framework, to back up what I’m talking about.

Addendum 1: Outsourcers
If you are deploying systems to outsourcers, there need to be changes to the above. Outsourcers should not be given tools in such a state of flux, period. If you can’t lock something down, you are doing outsourcing wrong, or you shouldn’t be outsourcing it. Once it is locked down, go ahead and document it, and it is the job of the developers who manage the outsourcers to keep the documentation up to date and to roll out changes.

Addendum 2: Wikis
Hailed years back as the answer to documentation problems, wikis haven’t worked (and I’m sure we’ll see the same with Google Docs if we continue the current trend). The reason is primarily (IMO) that Wikis use a system of organization completely different than a Word document. It is non-hierarchical, non-procedural, and has no organization. It makes a Wiki wonderfully suited to describe things (it works great as an encyclopedia), but terrible at documenting processes. A proper wiki has lots of cross references and modular information. How useful is this to document workflows? I’d say it is counterproductive, as I know I’ve been enticed to spend an entire afternoon adding dozens of pages to a wiki that ultimately actually give too much information for the user and are hard to follow. So all you’re left with on most wikis is a bunch of pages that basically read like Word docs anyway (all slash commands in the game, what the different fields of Tool X mean), with a shittier text editor than Word and equally inconvenient way of accessing information. Which is why I’d prefer google docs- it does away with all the pretentious wiki bullshit and just gives you a bunch of actual documents, that are easier to collaborate on (in real time!).

What’s wrong with Autodesk? Part I, Feedback Mechanisms

In the past month, I was part of a conference call with Autodesk and industry technical artists about integrating .NET into Maya (and how we use it in game development), and a couple weeks later we also had a couple Autodesk reps visit BioWare Austin to talk about their consulting services and get feedback. Both were very honest and constructive discussions. I said what I wanted to say and felt I got honest answers. It was fun to take them to task about a variety of things, but more importantly, it gave me a much more nuanced understanding of the external problems with the company. I’m going to go over them in the next series of blog posts.

Problem 1: Feedback Mechanisms

Once, when a woman made a request of him as he passed by on a journey, he at first said to her, “I haven’t time,” but afterwards, when she cried out, “Cease, then, being emperor,” he turned about and granted her a hearing. -Cassius Dio, Roman Histories, 69.6.3

The above is a famous quote about the Emperor Hadrian, who was famously approachable. It is this lack of approachability that is the first and most fundamental correctable problem with Autodesk. There is simply no good feedback mechanism for Autodesk users. (I’ll explain in my next post how this is technically false but effectively true). Whenever I rip on AD to their faces, I always have brief guilt when they respond with ‘You need to tell us about it so we can fix it.’ And they are, of course, correct.

I have the same issue with my tools at work- if people are having issues, I need them to tell me about them. Every day. Until I do something, even if that only means getting it into Hansoft and on the schedule. But they don’t- the teams that do it the best have been cultured to do it. The animation team, which I’ve worked with the longest and thus has the longest history of support, is the best at requesting tools and demanding support. The environment team, which has traditionally had little and poor quality support (though, admittedly, far simpler requirements) often doesn’t respond even when things are crashing.

I think we, as AD customers, suffer like my environment team does. We are not used to getting support from AD and are unsure of the people we’re dealing with. This falls squarely on AD’s shoulders; when we report issues, we need acknowledgment even if we can’t get immediate results. When we see changes, we need to know what prompted them, and we need to know when our prompting causes changes.

In most ways, my position and Autodesk’s is fundamentally the same- we are both tools producers. The difference is the route feedback and requests take. In my case, they all must be balanced against a schedule driving towards a creative vision (a videogame, film, whatever). The people using the tool must communicate upwards to the people scheduling me, and they schedule me to work on what they deem most important. There’s conflicting pressure from below (users) and above (planners). In AD’s case, there is not that conflicting pressure. It is the users that should be driving the development of the middleware. It is still important for AD to provide a vision (and I don’t believe they have the right people to do this right now), such as ‘a plugin model architecture’ or ‘bloated with features’, but that vision is only relevant towards how it accomplishes customer requirements (‘creating a clean API’ or ‘writing a closed but fast tool’).

This lack of feedback mechanism is undoubtedly the biggest problem I have with Autodesk- they are a company that doesn’t seem to communicate with their users. But there’s actually a dirty little secret only the most privileged of lead artists at the most wealthy of studios know: Autodesk actually has important and serious feedback mechanisms. Confused? You should be.

The Development Isolation Layer

Joel Spolsky over at Joel on Software has an excellent article from 2006, called “The Development Abstraction Layer.” The gist of it is that, developers must be abstracted from the distractions of business.

Management’s primary responsibility to create the illusion that a software company can be run by writing code, because that’s what programmers do. And while it would be great to have programmers who are also great at sales, graphic design, system administration, and cooking, it’s unrealistic. Like teaching a pig to sing, it wastes your time and it annoys the pig.

The article is spot on in its advice and ideas. However, I think there is a dangerous trend in game and software development- well, let’s not call it a trend, as it is more like an industry standard- that developers are over abstracted, and become isolated. What starts out as the sane and desirable abstraction Joel describes has morphed into a management-heavy, control of information you find in many of today’s large studios. They are manifested by Project Managers.
The job of project management is to be a key component of the ‘Development Implementation Layer,’ the substructure Joel describes that takes care of all the non-programming business needs. Project managers keep track of schedules. That means, they need to make sure things happen when they are supposed to happen, whether it is the delivery of a feature from your team or (more importantly) other teams, an IT request, or that corporate is getting those licenses for that software we requested.

This really just involves speaking to people and other teams, and writing a schedule for everything (even if, because they lack production skills, they can’t actually change the schedule). And since they’re doing all that anyway, why bother having the developers do any of this? And as long as I’m here, why don’t I just speak for/as the team?

Isn’t that just the evolution of abstracting distractions?

So what you get are meetings composed 50% of project managers, and a loss of communication between departments. You never get feature requests or bugs directly, they all have to be routed through the developer/tool user/QA, to their PM, to your PM, and then probably through your lead, before it gets to you (if it does at all). No one from another department is allowed to go to you with a question directly (unless they know you and can just ask you in person or over IM), even if it is a question that you can answer in seconds- it is routed through two project managers and maybe a lead.

This is really just the Law of Leaky Abstractions in effect. Except written by a programmer who is really fond over over-abstracting everything. You are forced to use an over-abstracted framework, which only gives you a few ways to change things in a complex underlying system. Except there’s no way to abstract some of what I need it to do, or what it needs of me, so I end up having to jump through extra hoops to add two numbers in a place where the framework won’t let me but I know it is what I want to do and it makes sense.

Project management is something like that. Their abstractions are fundamentally leaky. Or maybe not. Maybe they are actually valves that need to expunged, but project management doesn’t have a bucket and doesn’t want to disturb you by asking for yours, even though you’re going to have to mop the fucking floor anyway.

Obviously these over-abstractions don’t work. We need to discuss with other teams, coordinate schedules because it influences how we work, and we can’t just have one lead alongside a PM stand in for three, four, or a dozen developers. If we don’t have a direct line to our customers, we’re going to be ineffective. And a direct line doesn’t mean an open door at all hours, or a pager that goes off whenever a tool crashes. It means, we need to have all information about what can potentially impact what we are working on and will need to work on. We don’t need to respond to every piece of info, or read it every day, but we need to have it and filter it ourselves- having a few people control all information is a recipe for disaster.

But large studios do exactly that anyway. PMs are there to abstract, but end up isolating. It isn’t a PM’s job to decide what I need to know about what someone else is working on, and it sure as fuck is not a PM’s job (or a lead’s job, for that matter) to filter out customer feedback on the code I write and maintain. It is their job to make sure I know my priorities and schedule, and that’s about it.

-Rob

Generic Interfaces/Abstract Base Classes

I want to show a really useful pattern I’ve been taking advantage of recently.

public interface IXElementSerializable
	where T : IXElementSerializable
{
	T Deserialize(XElement element);
	XElement Serialize();
}

public class MyType : IXElementSerializable
{
	public MyType Deserialize(XElement element)
	{
		…
	}
	public XElement Serialize()
	{
		…
	}
}

I find it super useful, as you can return the type itself in the interface/implementation, rather than the interface type. Using the generic constraint also makes it clear how to use the interface. You can also use it on abstract methods/properties on abstract base classes, that you want to return the subtype. That’s all there is to it.

Math Libraries

.NET 3d math libraries are a bit strange. There are a few options available- arguably the best one, XNA, only works for 32 bit. If you want an x64 math library, your pickings are slim. So, after having been through a number of the public offerings available, and having dabbled in rolling my own a couple times, here are some of my pet peeves, comments, questions, and desires.

Use double (System.Double), not float (System.Single)
The most common rebuttal to a lot of my arguments is going to be “performance” (including memory), but I really, really think any native .NET math library should use double by default. floats (aka, System.Single) are only beneficial from a memory standpoint, despite what some may say- processors actually calculate at a higher precision and truncate down to fit the desired memory. I’d give you a reference but that statement is only from the word of some very reputable programmers, so you can look it up yourself if you disagree. double is the default C (and C#) floating point number type, and I feel it should be in any standard library (it already is in System.Math). The other thing to consider is the customer. Is this a developer and tool-facing library? Or will this be used in game runtimes? Either way, I’d rather start with a good, robust, reusable library, than one that is generic-tuned for better performance but you will probably end up tweaking it for performance more anyway. So, use doubles instead of floats, and you can optimize it later.

Use properties, not fields
A real pet peeve, which doesn’t have performance implications, is using public fields instead of public properties. This is class design 101 and I don’t believe it needs explanation, but I see it over and over. Use properties, not fields.

Methods without side effects
Don’t give me a ‘Normalize()’ method that will mutate my vector. Give me a ‘Normalized()’ method that will return ‘this’ vector normalized. Actually this is one instance of a much bigger issue:

Math classes should be immutable!
Well this is a common one to not think about. Let me ask, if you do something like:

double d1 = 5.0d;
double d2 = d1;
d1 += 1; //d2 is still equal to 5.0d!

are you changing the value of ‘d1′ or are you changing the value of ’5.0′? Well, neither exactly, but you are certainly not changing the value of ’5.0′, and you are not changing the value of ‘d2′. d2 refers to an instance of a System.Double that has and forever will have a value of 5.0d. You can change what value d2 refers to, but you cannot change the value of the value. That said, why do we create libraries where this is legal?

Vector3 v1 = new Vector3();
Vector3 v2 = v1;
v1 += 1.0d; //v2's value has changed!

What I’d much rather see is fully-immutable classes, so that we have:

Vector3 v1 = new Vector3();
Vector3 v2 = v1;
v1 += 1.0d; //compiler error!
v1 = v1 + 1.0d; //this works, and v2 still has the same value

Using immutable classes also fixes problems like:

Use constructors, not mutation
I hate stuff like

Vector3 v;
v.X = 1;
v.Y = 2.5;
v.Z = 3.0;
return v;

rather than

return new Vector3(1, 2.5, 3.0);

If you use immutable classes, the former would be impossible, so problem solved.

Duplicated code
This, along with float/double, is the other performance consideration. Apparently the JIT may or may not inline some method calls, so duplicating code inside a method may be faster. A balance must be struck- duplicate as little code as possible, while making the code as easily understandable and refactorable as possible. I have written crazy ways to get full code reuse, that ended up being somewhat slower, but much more difficult to follow, so I abandoned it (though I may show the idea in a future post). So, in order to walk this line well:

Three (or more) different ways to do the same thing
There’s no reason to give give “public static Vector3 Add(Vector3 v1, Vector3 v2)”, “public Vector3 Add(Vector3 other)”, and “public static Vector3 operator +(Vector3 v1, Vector3 v2)” (and immutability means you’d never want “public void Vector3 Add(Vector3 other)”, right?). Give me two at most- the static ‘Add’ method is unnecessary and the worst way to call the method. If you are going to reuse code extensively, it is more acceptable, but if you’re re-writing code, all those extra lines will add up when making changes or refactoring.

Make sure it works
In our internal EA math library, I saw the following two methods:

public override int GetHashCode()
{
    return this.X.GetHashCode() + this.Y.GetHashCode();
}
public override bool Equals(Vector2 other)
{
    return other.X == this.X && other.Y == this.Y;
}

I can’t believe this requires a comment, quite honestly. The GetHashCode implementation is a joke- you are guaranteed to get any number of objects with the same hash code, and the distribution of those objects will all clump. Like, say, the vectors (10, -10) and (3, -3) and (0,0). The Equals comparison will obviously fail because comparing floating point binary types (doubles and floats) like that is never a good idea due to precision and general float math conundrums.

Use conversions
This is mostly personal preference. I’d rather have conversion operators to convert between Quaternion and Matrix, than ‘Quaternion.FromMatrix’ and ‘Matrix.FromQuaternion’ static methods. Of course, they should almost always be explicit, since implicit operators don’t make sense when going between different types of numbers like most math libraries have.

Final Comments
Two closing remarks. First, I’d suggest using F# if you are considering writing a custom math library. The performance of F# is blazing fast, and you’ll get a lot of these requests built in. Second, I understand there are things I overlooked and/or am no expert on. The focus of this is making an easily usable and maintainable library, something I think I do relatively well with; NOT a highly-performant library, which is something I’m less versed in and requires a deep understanding of the clr, what IL code your higher-level code compiles into, and other low(er) level issues.

Against Serialization with XmlSerialization

There’s a terrible monster in .NET’s closest, and its name is XmlSerialization. I love serialization to XML (or whatever your node-based text format of choice is), and I love XML in .NET and C#, but XmlSerialization is a horror. Let’s look at the requirements for XML serialization with the classes in System.Xml.XmlSerialization:

  1. XML serialization serializes only the public fields and read/write property values of an object.
  2. XML serialization requires a default constructor to be declared in the class that is to be serialized.

What is serialization useful for?

  1. Persist the state of objects.
  2. Modify XML documents without using the DOM.
  3. Pass an object across applications and domains.
  4. Pass an object anywhere as a string.

That is stuff that is not just useful, it is essential. The problems with XmlSerialization are the constraints it puts on class design. They are deal-breakers for me- any technology that places such requirements on class design as XmlSerialization is terrible in my eyes. If I wrote some technology that had the requirements of XmlSerialization, and distributed it, I’d get harangued, and rightly so (there are complaints against nHibernate because every property must be virtual, this is infinitely worse in comparison). So what are the constraints/problems?

Note: I’m going to use the word ‘entity’ for a class that should only have one instance per-identity. There should only ever be one instance of Widget with the ID ’50935′ which other objects refer to.

Only public properties with public getters and settings are serialized.
This is the first of two huge slaps to good class design. One goal of designing good code is exposing the minimal public interface possible. Many classes only need a few public property setters, but this requires making them all public. Also, you cannot persist data that only exists in protected properties. Finally, you need to err on the side of making everything public, rather than choosing the most protected access possible from the start. These requirements are in direct contradiction to the ‘do not expose the internals of your class’- anyone consuming your class needs to have full access to all persistent components.

Serializable classes require a parameterless constructor.
Yikes. Few classes I write have a parameterless constructor, especially ones that need to persist. Entities need some sort of identification that is usually part of the constructor- serializable classes can have many instances of the same data.

The above two points are the most severe, since they fly in of both entities, which should have a single instance, and immutable classes, which have no public setters.

Little control over how objects serialize.
This is important. If you have a property that holds a reference to a class, it will only serialize if that class is serializable. And if it is serializable, but it is an entity, it will serialize a new instance. Interfaces will not serialize AT ALL.

Overcoming constraints is complex!
You are able to program around most of these problems. But if you’re going to do that, you need to really examine why you are using XmlSerialization. I know from experience with multiple teams here that most XML serialization with XmlSerialization does what is much better handled through custom serialization routines. I’d always first try to use custom serialization, and only use the built-in XmlSerialization is absolutely necessary, namely when doing much more advanced things with XML, such as, assuring certain typesafeties, namespaces, standard compliance, etc, or for the representation of relatively simple data objects, such as user preferences. But I see it most often used for simple data persistence or passing of data between .NET applications, and in those cases it is never my method of choice.

So that’s just a fraction of my case against XmlSerialization. You can find many more problems on the internet, but you’ll have to look into it, because they are rarely phrased as serious problems- it is one of those technologies that unassuming cargo-cultists gravitate towards. They have little understanding of the intended usage, power, costs, and other options, but they use it anyway. In a future post, I’ll go over strategies for custom serialization and how they address the problems associated with XmlSerialization.

Extending LinqToXml for better XML interaction

Many tools programmers or tech artists work with XML on a daily basis.  For .NET developers, there are three ways to work with XML.  You can use XML serialization (built in or custom), the System.Xml namespace, or LinqToXml (System.Xml.Linq).  I usually advocate XML serialization (with custom serialization routines!), but there are times when that isn’t practical.

In our case, we had a few hand-maintaned xml files that supported our animation system, which was undergoing a heavy rewrite by the gameplay team. They don’t maintain the animation tools code, though, so the serializing logic we wrote for the xml could easily break. Even worse, they could break our entire system logic if they make a logical change! So it was really impossible to maintain a fully logical system with serializing classes, as we always desire.

So we wrote ‘utility’ methods to do what we needed to do, and only what we needed to do, using System.Xml and XPath expressions. However, as anyone that has had to decipher tools written this way will tell you, this is a maintenance nightmare. You need to understand all the nuance of the underlying code to write, and each time you write something you can easily break the xml, since you’re working really, truly with raw xml. So we developed these ‘LinqToXml’ extensions to create a very light logical layer between underlying XML, representative classes, and procedural (utility) code.

Let’s take a look at an example XML file (vastly simplified):

<metadata>
  <actions>
    <input name="Stance">
      <value name="Standing" />
      <value name="Sitting" />
    </input>
    <input name="Weapon">
      <value name="Saber" />
      <value name="Gun" />
    </input>
  </inputs>
  <actions>
    <action name="Attack" blendInTime="0.1" blendOutTime="0.2">
      <path value="action|attack" />
      <input name="Stance" value="Standing" />
      <input name="Weapon" value="Saber" />
    </action>
    <action name="Heal" blendInTime="0.05" blendOutTime="0.03">
      <path value="action|heal" />
      <input name="Stance" value="Sitting" />
    </action>
  </actions>
</metadata>

Looking at the file, the reasons for a full logical system are obvious- validating the ‘input’ element on an action, for example.  But like I said, we needed to trade what’s right for what will work (we wrote the ‘right’ system for the xml 6 months ago, and the metadata system was changed right after that, invalidating some amount of work and resulting in a stagnation of the logical and serializing system for metadata).  Below is an example of the classes we would create to represent that XML.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace FluentXml
{
    public class MetadataAction : XElement
    {
        public string ActionName
        {
            get { return this.Attribute("name").Value; }
            set { this.Attribute("name").Value = value; }
        }
        public decimal BlendInTime
        {
            get { return decimal.Parse(this.Attribute("blendInTime").Value); }
            set { this.Attribute("blendInTime").Value = value.ToString(); }
        }
        public string NetworkPath
        {
            get { return this.Element("path").Attribute("value").Value; }
            set { this.Element("path").Attribute("value").Value = value; }
        }
        public Dictionary Inputs
        {
            get { return this.Elements("input").ToDictionary(input => input.Attribute("name").Value, input => input.Attribute("value").Value); }
            set
            {
                this.Elements("input").Remove();
                foreach (KeyValuePair kvp in value)
                {
                    this.Add(new XElement("input", new XAttribute("name", kvp.Key), new XAttribute("value", kvp.Value)));
                }
            }
        }

        public MetadataAction(XElement other)
            : base(other)
        {
        }
    }
    public class MetadataInput : XElement
    {
        public string InputName
        {
            get { return this.Attribute("name").Value; }
            set { this.Attribute("name").SetValue(value); }
        }
        public IEnumerable InputValues
        {
            get
            {
                foreach (XElement inputVal in this.Elements("value"))
                {
                    yield return inputVal.Attribute("name").Value;
                }
            }
            set
            {
                this.Elements("value").Remove();
                foreach (string valname in value)
                {
                    this.Add(new XElement("value", new XAttribute("name", valname)));
                }
            }
        }

        public MetadataInput(XElement other)
            : base(other)
        {
        }
    }

    public class MetadataFile : XElement
    {
        public MetadataFile(XElement other)
            : base(other)
        {
        }

        public IEnumerable Inputs()
        {
            foreach (XElement child in this.Element("inputs").Elements().ToList())
            {
                MetadataInput result = child as MetadataInput;
                if (result == null)
                {
                    result = new MetadataInput(child);
                    child.ReplaceWith(result);
                }
                yield return result;
            }
        }
        public IEnumerable Actions()
        {
            foreach (XElement child in this.Element("actions").Elements().ToList())
            {
                MetadataAction result = child as MetadataAction;
                if (result == null)
                {
                    result = new MetadataAction(child);
                    child.ReplaceWith(result);
                }
                yield return result;
            }
        }
        public MetadataAction Action(string actionName)
        {
            foreach (MetadataAction action in this.Actions())
            {
                if (action.ActionName.Equals(actionName))
                {
                    return action;
                }
            }
            return null;
        }
        public MetadataInput Input(string inputName)
        {
            foreach (MetadataInput item in this.Inputs())
            {
                if (item.InputName.Equals(inputName))
                {
                    return item;
                }
            }
            return null;
        }
    }
}

This is really just ‘glue’ code that works with the underlying XML directly, but in a much more easily maintained format; instead of difficult-to-decipher XPath expressions, the classes make an easy-to-understand interface to the xml. In addition, we can write very fluent and concise utility expressions, for querying or processing, such as:

MetadataFile aam = new MetadataFile(XElement.Load("XMLFile1.xml"));
IEnumerable allActionNames = aam.Actions().Select(a => a.ActionName);
aam.Input("Weapon").InputValues = new string[] { "test1", "test2" };
aam.Actions().Where(a => a.BlendInTime < 0.5m).ToList().ForEach(a => a.BlendInTime = 0.5m);
var inputsAndActionsUsing = aam.Inputs().Select(input => new { Input = input, Actions = from a in aam.Actions() where a.Inputs.ContainsKey(input.InputName) select a });

This is a bit of an advanced topic but for people who are used to LINQ (and especially Linq2Xml), it should make sense, and is very, very powerful. We replaced all of our XPath utility methods for Metadata with this system in a couple hours, and boy was it worth it. In a future post I’ll go over a few improvements we can make, such as using a base ‘MetadataElement’ class for validation and better reuse, improving our IEnumerable yield methods, and improving MetadataFile by making it an XDocument to preserve top-level comments and provide more intuitive use.

Blogging again!

I’m going to start blogging again (and more seriously for the first time).  I’ve been doing most of my posting over at www.tech-artists.org the past few years, but now with increased free time (no more crunch for me), and an expertise in a relevant area (I feel like I’m finally a competent enough .NET developer), I have some renewed reason to blog.  I’m going to aim to blog once week, no less than once a month, on topics mostly about game pipeline and .NET development.

Speaker at GDC 2009

I’ll be on a panel for “Technical Art Techniques” at GDC 2009.  I am so psyched about going, I can’t wait.  My bio (with awesome Sith photo) is here: https://www.cmpevents.com/GD09/a.asp?option=G&V=3&id=589097

Money is tight but it is always well worth it to go if possible.

Yes we can!

Not yes we did.  There is still lots of work to do.  Yes we can.

Return top
 

Switch to our mobile site