xml serializing of saved game data

♀尐吖头ヾ 提交于 2019-11-27 08:26:03

问题


I am trying to write a method to save some basing data for a game. At the moment I am trying to save data in an xml format with a parent <data> element containing an array of <leveldata> elements which have fields for index, completion and attempts. This is the first time I have tried to serialize anything in c# so I have run into a few issues, at the moment, it is falling over with an invalidoperationexception when I try to deserialize the file (detail of exception at bottom).

Here is the code.

public void SaveData()
{
    const string filename = "data.vision";

#if WINDOWS_PHONE
    IsolatedStorageFile dataFile = IsolatedStorageFile.GetUserStoreForApplication();
#else
    IsolatedStorageFile dataFile = IsolatedStorageFile.GetUserStoreForDomain();
#endif
    try
    {
        // Create an isolated storage stream and initialize it as null.
        IsolatedStorageFileStream isolatedFileStream = null;

        // Open the isolated storage stream, and write the save data file.
        if (dataFile.FileExists(filename))
        {
            using (isolatedFileStream = dataFile.OpenFile(filename, FileMode.Open,  FileAccess.ReadWrite))
            {
                // Read the data from the file.
                XmlSerializer serializer = new XmlSerializer(typeof(Data));
                // Store each of the deserialized data objects in the list.
                Data savedData = (Data)serializer.Deserialize(isolatedFileStream);


                // Loop through the saved data objects.
                for(int i = 0; i < savedData.Levels.Count; i++)
                {
                    // Get the data object in question.
                    LevelData levelData = savedData.Levels[i];

                    // Check to see if the index of the data object corresponds to the active level index.
                    if (levelData.Index == mLevelIndex)
                    {
                        // Check that the attempts already saved is less.
                        if (levelData.Attempts < mLevel.AttemptCounter)
                            levelData.Attempts = mLevel.AttemptCounter;

                        // Check that the 
                        if (levelData.PercentComplete < 50)
                            levelData.PercentComplete = 50;
                    }
                }
                serializer.Serialize(isolatedFileStream, savedData);
            }  
        }
        else
        {
            // If there is no data file, create a new one.
            using (isolatedFileStream = dataFile.CreateFile(filename))
            {
                // Check the file stream has been initialized.
                if (isolatedFileStream != null)
                {
                    // Create a new data object to store the meta data for the current level.
                    Data data = new Data();
                    // Create a list to store the data already saved.
                    data.Levels = new List<LevelData>();

                    // Initialize the new data values.
                    LevelData levelData = new LevelData();
                    levelData.Index = mLevelIndex;
                    levelData.Attempts = mLevel.AttemptCounter;
                    levelData.PercentComplete = 50;

                    // Add the level data.
                    data.Levels.Add(levelData);

                    // Convert the object to XML data and put it in the stream.
                    XmlSerializer serializer = new XmlSerializer(typeof(Data));
                    // Seriaize the data.
                    serializer.Serialize(isolatedFileStream, data);
                }
            }
        }
    }
    finally
    {
        // Dispose the storage file, in order to commit changes.
        dataFile.Dispose();
    }
}

DATA:

public struct Data
{
    /// <summary>
    /// The Level data object.
    /// </summary>
    [XmlArray(ElementName = "Levels")]
    public List<LevelData> Levels;
}

Level Data

public struct LevelData
{
    /// <summary>
    /// The index of the level.
    /// </summary>
    [XmlElement(ElementName = "Index")]
    public int Index;

    /// <summary>
    /// The number of attempts the player has made for a particular level.
    /// </summary>
    [XmlElement(ElementName = "Attempts")]
    public int Attempts;

    /// <summary>
    /// A value describing the furthest the player has ever got within the level.
    /// </summary>
    [XmlElement(ElementName = "PercentComplete")]
    public int PercentComplete;
}

Exception Detail:

{System.InvalidOperationException: There is an error in XML document (10, 10). ---> System.Xml.XmlException: Unexpected XML declaration. The XML declaration must be the first node in the document, and no white space characters are allowed to appear before it. Line 10, position 10.
   at System.Xml.XmlTextReaderImpl.Throw(Exception e)
   at System.Xml.XmlTextReaderImpl.Throw(String res, String arg)
   at System.Xml.XmlTextReaderImpl.ParsePI(BufferBuilder piInDtdStringBuilder)
   at System.Xml.XmlTextReaderImpl.ParseDocumentContent()
   at System.Xml.XmlTextReaderImpl.Read()
   at System.Xml.XmlReader.ReadEndElement()
   at System.Xml.Serialization.XmlSerializationReader.ReadEndElement()
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderData.Read3_Data(Boolean checkType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReaderData.Read4_Data()
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, Object events)
   at System.Xml.Serialization.XmlSerializer.Deserialize(Stream stream)
   at Vision.GameplayScreen.SaveData()
   at Vision.GameplayScreen.HandleInput(InputState input)
   at Vision.ScreenManager.Update(GameTime gameTime)
   at Microsoft.Xna.Framework.Game.<.cctor>b__19(IUpdateable updateable, GameTime gameTime)
   at Microsoft.Xna.Framework.Game.SortingFilteringCollection`1.ForEachFilteredItem[TUserData](Action`2 action, TUserData userData)
   at Microsoft.Xna.Framework.Game.Update(GameTime gameTime)
   at Vision.Game.Update(GameTime gameTime)
   at Microsoft.Xna.Framework.Game.DoUpdate(GameTime gameTime)
   at Microsoft.Xna.Framework.Game.Tick()
   at MonoGame.Framework.WindowsPhone.SurfaceUpdateHandler.Draw(Device device, DeviceContext context, RenderTargetView renderTargetView)
   at MonoGame.Framework.WindowsPhone.DrawingSurfaceUpdateHandler.DrawingSurfaceContentProvider.GetTexture(Size2F surfaceSize, DrawingSurfaceSynchronizedTexture& synchronizedTexture, RectangleF& textureSubRectangle)
   at SharpDX.Direct3D11.DrawingSurfaceContentProviderShadow.DrawingSurfaceContentProviderVtbl.GetTexture(IntPtr thisPtr, IntPtr surfaceSize, IntPtr synchronizedTexture, IntPtr textureSubRectangle)}

回答1:


Implement this after reading the file, and before deserialization:

isolatedFileStream.Position = 0;



回答2:


The code to serialize/deserialize is fine. The problem must be with your usage of the IsolatedStorageFileStream, in particular the fact that you are reusing the same stream to read and write. I'd suggest splitting it into two functions - one for saving and one for loading. Then you can call Load(), Edit(), Save(), or just Create() and Save() if the file does not exist.

Also, as mentioned it would be helpful to post the Xml as it currently exists on disk. It appears that it has been mangled by the load, save process.

I tested the serialization code in LINQPad like so:

void Main()
{
    var xml = Save();
    Console.WriteLine(xml);
    var data = Load(xml);
    Console.WriteLine("\r\nLevel count: " + data.Levels.Count.ToString());
}

// Define other methods and classes here
public struct LevelData
{
    /// <summary>
    /// The index of the level.
    /// </summary>
    [XmlElement(ElementName = "Index")]
    public int Index;

    /// <summary>
    /// The number of attempts the player has made for a particular level.
    /// </summary>
    [XmlElement(ElementName = "Attempts")]
    public int Attempts;

    /// <summary>
    /// A value describing the furthest the player has ever got within the level.
    /// </summary>
    [XmlElement(ElementName = "PercentComplete")]
    public int PercentComplete;
}

public struct Data
{
    /// <summary>
    /// The Level data object.
    /// </summary>
    [XmlArray(ElementName = "Levels")]
    public List<LevelData> Levels;
}

public string Save()
{
    Data data = new Data();
    // Create a list to store the data already saved.
    data.Levels = new List<LevelData>();

    // Initialize the new data values.
    LevelData levelData = new LevelData();
    levelData.Index = 1;
    levelData.Attempts = 3;
    levelData.PercentComplete = 50;

    // Add the level data.
    data.Levels.Add(levelData);

    // Convert the object to XML data and put it in the stream.
    XmlSerializer serializer = new XmlSerializer(typeof(Data));
    var sb = new StringBuilder();
    using (var sr = new StringWriter(sb))
    {
        // Seriaize the data.
        serializer.Serialize(sr, data);
    }
    return sb.ToString();
}

public Data Load(string xml)
{
    // Convert the object to XML data and put it in the stream.
    XmlSerializer serializer = new XmlSerializer(typeof(Data));
    using (var sr = new StringReader(xml))
    {
        return (Data)serializer.Deserialize(sr);
    }
}


来源:https://stackoverflow.com/questions/20286700/xml-serializing-of-saved-game-data

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!