xml file save/read error (making a highscore system for XNA game)
- by Eddy
i get an error after i write player name to the file for second or third time (An unhandled exception of type 'System.InvalidOperationException' occurred in System.Xml.dll
Additional information: There is an error in XML document (18, 17).)
(in highscores load method
In data = (HighScoreData)serializer.Deserialize(stream);
it stops)
the problem is that some how it adds additional "" at the end of my .dat file
could anyone tell me how to fix this?
the file before save looks:
<?xml version="1.0"?>
<HighScoreData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PlayerName>
<string>neil</string>
<string>shawn</string>
<string>mark</string>
<string>cindy</string>
<string>sam</string>
</PlayerName>
<Score>
<int>200</int>
<int>180</int>
<int>150</int>
<int>100</int>
<int>50</int>
</Score>
<Count>5</Count>
</HighScoreData>
the file after save looks:
<?xml version="1.0"?>
<HighScoreData xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<PlayerName>
<string>Nick</string>
<string>Nick</string>
<string>neil</string>
<string>shawn</string>
<string>mark</string>
</PlayerName>
<Score>
<int>210</int>
<int>210</int>
<int>200</int>
<int>180</int>
<int>150</int>
</Score>
<Count>5</Count>
</HighScoreData>>
the part of my code that does all of save load to xml is:
DECLARATIONS PART
[Serializable]
public struct HighScoreData
{
public string[] PlayerName;
public int[] Score;
public int Count;
public HighScoreData(int count)
{
PlayerName = new string[count];
Score = new int[count];
Count = count;
}
}
IAsyncResult result = null;
bool inputName;
HighScoreData data;
int Score = 0;
public string NAME;
public string HighScoresFilename = "highscores.dat";
Game1 constructor
public Game1()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
Width = graphics.PreferredBackBufferWidth = 960;
Height = graphics.PreferredBackBufferHeight =640;
GamerServicesComponent GSC = new GamerServicesComponent(this);
Components.Add(GSC);
}
Inicialize function (end of it)
protected override void Initialize()
{
//other game code
base.Initialize();
string fullpath =Path.Combine(HighScoresFilename);
if (!File.Exists(fullpath))
{
//If the file doesn't exist, make a fake one...
// Create the data to save
data = new HighScoreData(5);
data.PlayerName[0] = "neil";
data.Score[0] = 200;
data.PlayerName[1] = "shawn";
data.Score[1] = 180;
data.PlayerName[2] = "mark";
data.Score[2] = 150;
data.PlayerName[3] = "cindy";
data.Score[3] = 100;
data.PlayerName[4] = "sam";
data.Score[4] = 50;
SaveHighScores(data, HighScoresFilename);
}
}
all methods for loading saving and output
public static void SaveHighScores(HighScoreData data, string filename)
{
// Get the path of the save game
string fullpath = Path.Combine("highscores.dat");
// Open the file, creating it if necessary
FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate);
try
{
// Convert the object to XML data and put it in the stream
XmlSerializer serializer = new XmlSerializer(typeof(HighScoreData));
serializer.Serialize(stream, data);
}
finally
{
// Close the file
stream.Close();
}
}
/* Load highscores */
public static HighScoreData LoadHighScores(string filename)
{
HighScoreData data;
// Get the path of the save game
string fullpath = Path.Combine("highscores.dat");
// Open the file
FileStream stream = File.Open(fullpath, FileMode.OpenOrCreate, FileAccess.Read);
try
{
// Read the data from the file
XmlSerializer serializer = new XmlSerializer(typeof(HighScoreData));
data = (HighScoreData)serializer.Deserialize(stream);//this is the line
// where program gives an error
}
finally
{
// Close the file
stream.Close();
}
return (data);
}
/* Save player highscore when game ends */
private void SaveHighScore()
{
// Create the data to saved
HighScoreData data = LoadHighScores(HighScoresFilename);
int scoreIndex = -1;
for (int i = 0; i < data.Count ; i++)
{
if (Score > data.Score[i])
{
scoreIndex = i;
break;
}
}
if (scoreIndex > -1)
{
//New high score found ... do swaps
for (int i = data.Count - 1; i > scoreIndex; i--)
{
data.PlayerName[i] = data.PlayerName[i - 1];
data.Score[i] = data.Score[i - 1];
}
data.PlayerName[scoreIndex] = NAME; //Retrieve User Name Here
data.Score[scoreIndex] = Score; // Retrieve score here
SaveHighScores(data, HighScoresFilename);
}
}
/* Iterate through data if highscore is called and make the string to be saved*/
public string makeHighScoreString()
{
// Create the data to save
HighScoreData data2 = LoadHighScores(HighScoresFilename);
// Create scoreBoardString
string scoreBoardString = "Highscores:\n\n";
for (int i = 0; i<5;i++)
{
scoreBoardString = scoreBoardString + data2.PlayerName[i] + "-" + data2.Score[i] + "\n";
}
return scoreBoardString;
}
when ill make this work i will start this code when i call game over (now i start it when i press some buttons, so i could test it faster)
public void InputYourName()
{
if (result == null && !Guide.IsVisible)
{
string title = "Name";
string description = "Write your name in order to save your Score";
string defaultText = "Nick";
PlayerIndex playerIndex = new PlayerIndex();
result= Guide.BeginShowKeyboardInput(playerIndex, title, description, defaultText, null, null);
// NAME = result.ToString();
}
if (result != null && result.IsCompleted)
{
NAME = Guide.EndShowKeyboardInput(result);
result = null;
inputName = false;
SaveHighScore();
}
}
this where i call output to the screen (ill call this in highscores meniu section when i am done with debugging)
spriteBatch.DrawString(Font1, "" + makeHighScoreString(),new Vector2(500,200), Color.White);
}