Saving to file

Sep 29, 2011 at 6:39 PM

Hey guys,

how would you implement saving the controls to a xml-file?

I tried the following:

public bool Save(string path)
        {
            try
            {
                XmlDocument doc = new XmlDocument();
                XmlNode root = doc.CreateElement("Controls");

                foreach (PlayerIndex key in PlayerControls.Keys)
                {
                    XmlNode child = doc.CreateElement(key.ToString());

                    foreach (string childKey in PlayerControls[key].Keys)
                    {
                        XmlNode secondChild = doc.CreateElement(childKey);
                        XmlAttribute attribute = doc.CreateAttribute("method");
                        attribute.Value = PlayerControls[key][childKey].ToString(); //This is where I have problems...
                        secondChild.Attributes.Append(attribute);
                        child.AppendChild(secondChild);
                    }

                    root.AppendChild(child);
                }

                doc.AppendChild(root);
                doc.Save(path);
            }
            catch
            {
                return false;
            }

            return true;
        }

Well, the problem is that there seems to be no easy way of saving the delegate as a string and I don't know how I can manage to do this. So, please help me. Maybe it's just because I'm stupid right now, but I just don't get it to work.

Thanks for helping,

RoBaaaT

 

PS: Sorry for bad english. I'm German.

Coordinator
Oct 2, 2011 at 3:46 AM

RoBaaT,

As far as I know, there are no easy ways to serialize a delegate in a manner that can be restored properly later.

However, one thing that you could do instead is take advantage of the fact that all of the existing sources and delegates for XnaInput can be chosen via a string, and store a string describing the InputMethod instead. You just need to have your configuration objects responsible for setting the InputMethods in the first place, so that you are aware of which method is being used, because there isn't a reverse delegate->name mapping included in the library. If you create any new delegates, you will need to create your own means of looking them up by name.

I hope this suggestion helps. If you create a complete saving and loading system for XnaInput, would you mind sharing the resulting code? I have a github repo for the project now and I could add you as a contributor, if you're interested.

-shader

Oct 4, 2011 at 5:12 PM
Edited Oct 4, 2011 at 5:23 PM

Shader,

I came up with another solution, which is using a struct named Control instead of InputMethod.

Control contains a string with the code for the delegate and an InputMethod, which gets instanced in the constructor of Control like this:

 

public Control(string methodCode, InputManager manager)
        {
            MethodCode = methodCode;

            Assembly assembly;
            Type delegateClass;
            MethodInfo delegateMethod;
            object obj;

            CompilerParameters parameters = new CompilerParameters(null, string.Empty, false);
            parameters.GenerateExecutable = false;
            parameters.GenerateInMemory = true;
            parameters.ReferencedAssemblies.Add("XnaInput.dll");
            parameters.ReferencedAssemblies.Add(@"C:\Program Files\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.dll");      
            parameters.ReferencedAssemblies.Add(@"C:\Program Files\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86\Microsoft.Xna.Framework.Game.dll"); //Is there any way of getting the path of the Xna assemblies independend of the computer?
            string code =      
                "using XnaInput;\n" +
                "using Microsoft.Xna.Framework;\n" +
                "using Microsoft.Xna.Framework.Input;\n" +
                "public class DelegateGenerator\n" +
                "{\n" +
                "   public InputMethod GenerateDelegate(InputManager manager)\n" +
                "   {\n" +
                "   return delegate { " + methodCode + " };\n" +
                "   }\n" +
                "}";

            CompilerResults res = new CSharpCodeProvider().CompileAssemblyFromSource(parameters, code);

            if (res.Errors.Count > 0)
                throw new ArgumentException("methodCode is not valid!");
  
            assembly = res.CompiledAssembly;
            delegateClass = assembly.GetType("DelegateGenerator");
            delegateMethod = delegateClass.GetMethod("GenerateDelegate");

            obj = Activator.CreateInstance(delegateClass);
            InputMethod = (InputMethod)delegateMethod.Invoke(obj, new object[] { manager });
        }

In the Save-method I then just use the delegateCode as the InnerText of the XmlNode. Here's an example of the save-file:
 <Mappings>
  <One>
    <Left>return (manager.Mouse.State.LeftButton == ButtonState.Released) ? 1.0f : 0.0f;</Left>
    <Right>return (manager.Mouse.State.RightButton == ButtonState.Released) ? 1.0f : 0.0f;</Right>
    <Crouch>return -manager.GamePads[PlayerIndex.One].State.ThumbSticks.Left.Y;</Crouch>
  </One>
  <Two />
  <Three />
  <Four />
</Mappings>
A possible problem with this could be, that users could easily change the code for the InputMethods, which would cause the game to crash.
But I think it wouldn't be to hard to just encrypt the files and then decrypt them again when loading.
Second problem is that I found no way to load the Xna-Assemblies for compiling the InputMethod independent of the system the user has.

RoBaaaT