3

EDIT: Got an answer, I changed the list Inv in player to a list of int, and imported the items on initial load of the game into a Dictionary like so:

public static class InitLoad
{
    static List<ItemEquipmentWeapon> weapons;

    public static Dictionary<int, Item> ItemIDList = new Dictionary<int, Item>();

    public static void PreLoading()
    {

        string path, filePath, 
            weaponFile = @"\WeaponsItem.aid";
        XmlSerializer SerializerObj;
        FileStream ReadFileStream;

        path = string.Format(@"{0}\AwesomeRPG\Data\Items",
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
        filePath = string.Format(@"{0}\{1}", path, weaponFile);
        SerializerObj = new XmlSerializer(typeof(ItemEquipmentWeapon));
        ReadFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        weapons = (List<ItemEquipmentWeapon>)SerializerObj.Deserialize(ReadFileStream);
        foreach (Item item in weapons)
        {
            ItemIDList.Add(item.ID, item);
        }
    }
}

Meaning I can then do this with my player class:

[Serializable()]
public class Player : Entity
{
    public string Name { get; set; }
    public int MaxHP { get; set; }
    public int Level { get; set; }
    public int XP { get; set; }
    public int Str { get; set; }
    public int End { get; set; }
    public int Dex { get; set; }
    public int Agi { get; set; }
    public int Wis { get; set; }
    public int Int { get; set; }
    //Create a list of Item Id's for inventory
    public List<int> Inv { get; set; }

    private int lHand;
    private int rHand;

    public int LHand
    {
        get 
        { return lHand; }
        set
        {
            if (!value.THand)
            {
                lHand = value;
            }
            else lHand = null;
        }
    }
    public int RHand
    {
        get 
        { return rHand; }
        set 
        { rHand = value; }
    }

    internal Player() { }
    public Player(string name, int maxhp, int hp, int lvl, int exp, int str, int end, int dex, int agi, int wis, int inte)
        : base(true, hp)
    {
        Name = name;
        MaxHP = maxhp;
        Level = lvl;
        XP = exp;
        Str = str;
        End = end;
        Dex = dex;
        Agi = agi;
        Wis = wis;
        Int = inte;

        Inv = new List<int>();
    }

    public List<string> GetInv()
    {
        List<string> val = new List<string>();
        Item item;
        foreach (int i in Inv)
        {
            InitLoad.ItemIDList.TryGetValue(i, out item);
            val.Add(item.Name);
        }

        return val;
    }

    public void AddItem(Item i, int amt)
    {
        for (int j = 0; j < amt; j++)
        {
            Inv.Add(i.ID);
        }
    }
    public void AddItem(Item i){
        AddItem(i, 1); }

    public void RemoveItem(Item i, int amt)
    {
        int count = 0;

        foreach (int item in Inv)
        {
            if (item == i.ID)
            {
                Inv.Remove(item);
                count++;
            }
            if (count == amt)
            {
                break;
            }
        }
    }
    public void RemoveItem(Item i){
        RemoveItem(i, 1); }

    public bool HasItem(Item i, int amt)
    {
        int count = 0;

        foreach (int item in Inv)
        {
            if (item == i.ID)
            {
                count++;
            }
        }

        return count >= amt;
    }
    public bool HasItem(Item i){
        return HasItem(i, 1); }
}

Hope this helps anybody else!

Original Question:

So, I'm making a silly little RPG game with windows forms to test my skills, and I'm sorting out saving. At the moment it saves to an XML file, which a custom extention (.asd) Here's my save/load code:

public static class SaveGame
{
    public static void Save(Player player)
    {
        string myfile = string.Format(@"{1}\AwesomeRPG\Saves\{0}Save.asd", player.Name, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));
        //Delete file if it already exists
        if (File.Exists(myfile)) System.IO.File.Delete(myfile);
        //Create/Write to the file
        FileStream outFile = File.Create(myfile);            
        XmlSerializer Serializer = new XmlSerializer(typeof(Player));
        Serializer.Serialize(outFile, player);
        outFile.Close();
    }

    public static Player Load(string FileName)
    {
        string myfile = string.Format(@"{1}\AwesomeRPG\Saves\{0}Save.asd", FileName, Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

        if (!File.Exists(myfile)) return null;
        XmlSerializer Serializer = new XmlSerializer(typeof(Player));
        FileStream ReadFileStream = new FileStream(myfile, FileMode.Open, FileAccess.Read, FileShare.Read);
        return (Player)Serializer.Deserialize(ReadFileStream);
    }
}

As you can imagine, this saves all the details of any item in the Inv list. However, I want all items that exist to be loaded (instances of them to be created) when the game starts, and I need a way for the save file to hold references to those instances, rather than making new instances.

The instances loaded when the game starts are also held in XML files, and then loaded into separate lists based on the item type, eg all ItemEquipmentWeapon instances (Inherits ItemEquipment which inherits Item) are in a WeaponItem.aid file, which is in XML format, and is loaded into a List

Is there any way I can save and load the Inv contents to and from the player save file by reference so I can have them use the existing instances setup during initial loading?

EDIT: Just thought, it might help some to see how the Player class is coded, so here it is:

[Serializable()]
public class Player : Entity
{
    public string Name { get; set; }
    public int MaxHP { get; set; }
    public int Level { get; set; }
    public int XP { get; set; }
    public int Str { get; set; }
    public int End { get; set; }
    public int Dex { get; set; }
    public int Agi { get; set; }
    public int Wis { get; set; }
    public int Int { get; set; }

    public List<Item> Inv { get; set; }

    private ItemEquipmentWeapon lHand;
    private ItemEquipmentWeapon rHand;

    public ItemEquipmentWeapon LHand
    {
        get 
        { return lHand; }
        set
        {
            if (!value.THand)
            {
                lHand = value;
            }
            else lHand = null;
        }
    }
    public ItemEquipmentWeapon RHand
    {
        get 
        { return rHand; }
        set 
        { rHand = value; }
    }

    internal Player() { }
    public Player(string name, int maxhp, int hp, int lvl, int exp, int str, int end, int dex, int agi, int wis, int inte)
        : base(true, hp)
    {
        Name = name;
        MaxHP = maxhp;
        Level = lvl;
        XP = exp;
        Str = str;
        End = end;
        Dex = dex;
        Agi = agi;
        Wis = wis;
        Int = inte;

        Inv = new List<Item>();
    }

    public List<string> GetInv()
    {
        List<string> val = new List<string>();

        foreach (Item item in Inv)
        {
            val.Add(item.Name);
        }

        return val;
    }

    public void AddItem(Item i, int amt)
    {
        for (int j = 0; j < amt; j++)
        {
            Inv.Add(i);
        }
    }
    public void AddItem(Item i){
        AddItem(i, 1); }

    public void RemoveItem(Item i, int amt)
    {
        int count = 0;

        foreach (Item item in Inv)
        {
            if (item == i)
            {
                Inv.Remove(item);
                count++;
            }
            if (count == amt)
            {
                break;
            }
        }
    }
    public void RemoveItem(Item i){
        RemoveItem(i, 1); }

    public bool HasItem(Item i, int amt)
    {
        int count = 0;

        foreach (Item item in Inv)
        {
            if (item == i)
            {
                count++;
            }
        }

        return count >= amt;
    }
    public bool HasItem(Item i){
        return HasItem(i, 1); }
}

Obviously the code that loads the item instances from XML on game load would also be very useful, but I haven't coded that yet, I'm not 100% sure how I would go about doing it. So far though, I have this:

public static class InitLoad
{
    static List<ItemEquipmentWeapon> weapons;

    public static void PreLoading()
    {
        string path, filePath, 
            weaponFile = @"\WeaponsItem.aid";
        XmlSerializer SerializerObj;
        FileStream ReadFileStream;

        path = string.Format(@"{0}\AwesomeRPG\Data\Items",
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData));

        filePath = string.Format(@"{0}\{1}", path, weaponFile);
        SerializerObj = new XmlSerializer(typeof(ItemEquipmentWeapon));
        ReadFileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read);
        weapons = (List<ItemEquipmentWeapon>)SerializerObj.Deserialize(ReadFileStream);
    }
}

Thanks in advance for any help!

Mayube
  • 203
  • 3
  • 12

1 Answers1

2

Is there any way I can save and load the Inv contents to and from the player save file by reference so I can have them use the existing instances setup during initial loading?

Here is one way to solve this issue:
1. Add to your Item class int field Id or something of the kind, and assign for each unique item appropriate unique value.
2. During initial loading create a global cache of all the unique items in your game. For this matter I'd suggest using Dictionary<int, Item> where the key would be Id of the item and value would be the item itself.
3. In your Player class you should store only Id's of the items, so during loading you can obtain instances of Item from the global cache mentioned previously.

Furthermore, you might want to read about flyweight pattern, which is pretty much about sharing instances.

Yurii
  • 4,811
  • 7
  • 32
  • 41
  • Oh, for the GetInv method in the player class, how would I pass the class the dictionary from InitLoad so it can lookup the names of the items from the ID's? – Mayube Nov 25 '13 at 17:56
  • @user3033160 Well, ideally you shouldn't pass that dictionary to your `Player.GetInv` method. 'Global' means that it should be accessible from any place in your program, so you might want to use either [Singleton](http://en.wikipedia.org/wiki/Singleton_pattern) pattern or declare that dictionary as public `public static Dictionary ItemsCache`. After that you can access it from `Player.GetInv` method as follows: `foreach(int id in Ids) { val.Add(InitLoad.ItemsCache[id].Name); }` – Yurii Nov 25 '13 at 18:11
  • Yeah, I made it public static in the class scope of the InitLoad.cs Because that class is in the Lib project, and both other projects reference Lib, it's accessible to all my code now, although it shouldn't be needed much outside of Lib. Thanks so much for your help! – Mayube Nov 25 '13 at 18:13