Search code examples
c#serializationxnamonogame

Why is my game serializing this class?


So I'm making a game, and it saves users' progress on the computer in a binary file. The User class stores a few things:

  1. Integers for stat values (Serializable)
  2. Strings for the Username and the skin assets
  3. Lists of both the Achievement class and the InventoryItem class, which I have created myself.

Here are the User fields:

    public string Username = "";
    // ID is used for local identification, as usernames can be changed.
    public int ID;

    public int Coins = 0;
    public List<Achievement> AchievementsCompleted = new List<Achievement>();
    public List<InventoryItem> Inventory = new List<InventoryItem>();
    public List<string> Skins = new List<string>();

    public string CurrentSkinAsset { get; set; }

The Achievement class stores ints, bools, and strings, which are all serializable. The InventoryItem class stores its name (a string) and an InventoryAction, which is a delegate that is called when the item is used.

These are the Achievement class's fields:

    public int ID = 0;
    public string Name = "";
    public bool Earned = false;
    public string Description = "";
    public string Image;
    public AchievmentDifficulty Difficulty;
    public int CoinsOnCompletion = 0;

    public AchievementMethod OnCompletion;
    public AchievementCriteria CompletionCriteria;

    public bool Completed = false;

And here are the fields for the InventoryItem class:

    InventoryAction actionWhenUsed;
    public string Name;

    public string AssetName;

The source of the InventoryAction variables are in my XNAGame class. What I mean by this is that the XNAGame class has a method called "UseSword()" or whatever, which it passes into the InventoryItem class. Previously, the methods were stored in the Game1 class, but the Game class, which Game1 inherits from, is not serializable, and there's no way for me to control that. This is why I have an XNAGame class.

I get an error when trying to serialize: "The 'SpriteFont' class is not marked as serializable", or something like that. Well, there is a SpriteFont object in my XNAGame class, and some quick tests showed that this is the source of the issue. Well, I have no control over whether or not the SpriteFont class is Serializable.

Why is the game doing this? Why must all the fields in the XNAGame class be serializable, when all I need is a few methods?

Keep in mind when answering that I'm 13, and may not understand all the terms you're using. If you need any code samples, I'll be glad to provide them for you. Thanks in advance!

EDIT: One solution I have thought of is to store the InventoryAction delegates in a Dictionary, except that this will be a pain and isn't very good programming practice. If this is the only way, I'll accept it, though (Honestly at this point I think this is the best solution).

EDIT 2: Here's the code for the User.Serialize method (I know what I'm doing in inefficient, and I should use a database, blah, blah, blah. I'm fine with what I'm doing now, so bear with me.):

        FileStream fileStream = null;
        List<User> users;
        BinaryFormatter binaryFormatter = new BinaryFormatter();
        try
        {
            if (File.Exists(FILE_PATH) && !IsFileLocked(FILE_PATH))
            {
                fileStream = File.Open(FILE_PATH, FileMode.Open);
                users = (List<User>)binaryFormatter.Deserialize(fileStream);
            }
            else
            {
                fileStream = File.Create(FILE_PATH);
                users = new List<User>();
            }

            for (int i = 0; i < users.Count; i++)
            {
                if (users[i].ID == this.ID)
                {
                    users.Remove(users[i]);
                }
            }

            foreach (Achievement a in AchievementsCompleted)
            {
                if (a.CompletionCriteria != null)
                {
                    a.CompletionCriteria = null;
                }
                if (a.OnCompletion != null)
                {
                    a.OnCompletion = null;
                }
            }

            users.Add(this);
            fileStream.Position = 0;
            binaryFormatter.Serialize(fileStream, users);

Solution

  • Okay, so I figured it out.

    The best solution was to use a Dictionary in the XNAGame class, which stores two things: an ItemType (an enumeration), and an InventoryAction. Basically, when I use an item, I check it's type and then look up it's method. Thanks to everyone who tried, and I'm sorry if the question was confusing.