Accessing a Service from within an XNA Content Pipeline Extension

Posted by David Wallace on Stack Overflow See other posts from Stack Overflow or by David Wallace
Published on 2012-04-03T16:44:32Z Indexed on 2012/04/09 11:30 UTC
Read the original article Hit count: 500

Filed under:
|
|
|
|

I need to allow my content pipeline extension to use a pattern similar to a factory. I start with a dictionary type:

public delegate T Mapper<T>(MapFactory<T> mf, XElement d);

public class MapFactory<T>
{
    Dictionary<string, Mapper<T>> map = new Dictionary<string, Mapper<T>>();

    public void Add(string s, Mapper<T> m)
    {
        map.Add(s, m);
    }

    public T Get(XElement xe)
    {
        if (xe == null) throw new ArgumentNullException(
            "Invalid document");
        var key = xe.Name.ToString();
        if (!map.ContainsKey(key)) throw new ArgumentException(
            key + " is not a valid key.");
        return map[key](this, xe);
    }

    public IEnumerable<T> GetAll(XElement xe)
    {
        if (xe == null) throw new ArgumentNullException(
            "Invalid document");
        foreach (var e in xe.Elements())
        {
            var val = e.Name.ToString();
            if (map.ContainsKey(val))
                yield return map[val](this, e);
        }
    }
}

Here is one type of object I want to store:

public partial class TestContent
{
    // Test type
    public string title;

    // Once test if true
    public bool once;

    // Parameters
    public Dictionary<string, object> args;

    public TestContent()
    {
        title = string.Empty;
        args = new Dictionary<string, object>();
    }

    public TestContent(XElement xe)
    {
        title = xe.Name.ToString();
        args = new Dictionary<string, object>();
        xe.ParseAttribute("once", once);
    }
}

XElement.ParseAttribute is an extension method that works as one might expect. It returns a boolean that is true if successful.

The issue is that I have many different types of tests, each of which populates the object in a way unique to the specific test. The element name is the key to MapFactory's dictionary. This type of test, while atypical, illustrates my problem.

public class LogicTest : TestBase
{
    string opkey;
    List<TestBase> items;

    public override bool Test(BehaviorArgs args)
    {
        if (items == null) return false;
        if (items.Count == 0) return false;
        bool result = items[0].Test(args);
        for (int i = 1; i < items.Count; i++)
        {
            bool other = items[i].Test(args);
            switch (opkey)
            {
                case "And":
                    result &= other;
                    if (!result) return false;
                    break;
                case "Or":
                    result |= other;
                    if (result) return true;
                    break;
                case "Xor":
                    result ^= other;
                    break;
                case "Nand":
                    result = !(result & other);
                    break;
                case "Nor":
                    result = !(result | other);
                    break;
                default:
                    result = false;
                    break;
            }
        }
        return result;
    }

    public static TestContent Build(MapFactory<TestContent> mf, XElement xe)
    {
        var result = new TestContent(xe);
        string key = "Or";
        xe.GetAttribute("op", key);
        result.args.Add("key", key);
        var names = mf.GetAll(xe).ToList();
        if (names.Count() < 2) throw new ArgumentException(
              "LogicTest requires at least two entries.");
        result.args.Add("items", names);
        return result;
    }
}

My actual code is more involved as the factory has two dictionaries, one that turns an XElement into a content type to write and another used by the reader to create the actual game objects.

I need to build these factories in code because they map strings to delegates. I have a service that contains several of these factories. The mission is to make these factory classes available to a content processor. Neither the processor itself nor the context it uses as a parameter have any known hooks to attach an IServiceProvider or equivalent.

Any ideas?

© Stack Overflow or respective owner

Related posts about XNA

Related posts about extension