Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by desiloh · Sep 30, 2014 at 01:57 PM · c#persistence

Best way to persist data while we are in a not final version

I'm a beginner, I'm making a mobile game and I want to persist the user session in memory. So I've saw the "PERSISTENCE - SAVING AND LOADING DATA" tutorial (http://unity3d.com/es/learn/tutorials/modules/beginner/live-training-archive/persistence-data-saving-loading) and I've implemented it. But one of the problems I've found with it is that when I make a change and I delete something in the Session this exception appears:

 SerializationException: Field "xxxxx" not found in class Session
 System.Runtime.Serialization.Formatters.Binary.ObjectReader.ReadTypeMetadata (System.IO.BinaryReader reader, Boolean isRuntimeObject, Boolean hasTypeInfo) (at /Users/builduser/buildslave/mono-runtime-and-classlibs/build/mcs/class/corlib/System.Runtime.Serialization.Formatters.Binary/ObjectReader.cs:691)... 

I understand the problem here, I deleted one of the fields I've already saved in the class Session and now I'm trying to load it again. But my question is: Is there a better way to persist data than this one? Because if I release a version of my game and after that I want to make a change in the info I'm saving (for example, delete some parameters and add others more accurate), then it will produce this kind of problems.

Should I worry about it or there is something I'm missing?

Thanks a lot

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

4 Replies

· Add your reply
  • Sort: 
avatar image
3

Answer by _dns_ · Sep 30, 2014 at 03:25 PM

Hi, I faced this problem with different environments but not in Unity (yet). Searching for modern solutions in C#, I found this document about Data Contract serialization & versioning that may help you: http://msdn.microsoft.com/en-us/library/ms731138%28v=vs.110%29.aspx

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image desiloh · Sep 30, 2014 at 05:03 PM 0
Share

Thank you so much! I'm sure it will help! I'm going to investigate it more about it

avatar image
2

Answer by furic · May 02, 2016 at 09:09 AM

I ran into this problem too and following @dns has suggested, I found out the solution is pretty easy!

First, follow this answers and download system.runtime.serialization.dll, put it in the project, and set .Net 2.0 (not sure if it's necessary)

Then you are ready to use DataContract as:

 using System.Runtime.Serialization;
 
 [Serializable, DataContract]
 public class GameSave
 {
 
     [DataMember]
     public int myInt;
     [DataMember]
     public DateTime myDateTime;
     [DataMember]
     public bool myBool;
 
     [DataMember]
     public int addedIntInNewVersion;
 
 }

Tested in Editor and it's good. May test it in mobile and update this answer later.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image or113 · Feb 18, 2017 at 06:09 PM 0
Share

Could you elaborate how this helps on how this helps with different versions of the persistence data?

avatar image
1

Answer by HypnoticOwl · Sep 04, 2015 at 01:28 PM

I realize this question is a year old, but there are still 27 people following the question and I think I found a neat solution!

Basically I use dictionaries to store variables of the same type. They can be accessed in a similar way PlayerPrefs does this:

 mySaves.SetInt("VariableName", 23);
 int i = mySaves.GetInt("VariableName");

My starting point was the Unity tutorial mentioned in the question. All I added were functions to convert the dictionaries to strings and vice versa and some checks whether the variable you want exists. I also made sure that exeptions when trying to read your save file are handled and added code to use the PlayerPrefs instead, when the game is run in the WebPlayer.

This is how my save controller looks now: using UnityEngine; using System; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO;

 public class SaveController : MonoBehaviour {
 
     public static SaveController control;
     public string fileName = "myGame.save";
 
     private Dictionary<string, int> ints;
     private Dictionary<string, string> strings;
     
     private SaveGame save;
     private bool writeSave = false;
     private BinaryFormatter formatter;
 
     private void Awake ()
     {
         if (control != null && control != this)
         {
             Destroy(gameObject);
             return;
         }
         
         DontDestroyOnLoad(gameObject);
         control = this;
         
         formatter = new BinaryFormatter();
         
         if(!Load())
             save = new SaveGame();
     }
     
     private bool Load()
     {
         if (Application.isWebPlayer)
         {
             // Everything is in PlayerPrefs and doesn't have to be loaded
             Debug.Log("Loading everything from PlayerPrefs");
             return true;
         }
         else if(File.Exists(Application.persistentDataPath + "/"+fileName))
         {
             Debug.Log ("Loading " + Application.persistentDataPath + "/"+fileName);
 
             // Load File
             FileStream file = File.Open(Application.persistentDataPath + "/"+fileName, FileMode.Open);
             try
             {
                 save = (SaveGame)formatter.Deserialize(file);
             }
             catch
             {
                 Debug.LogWarning("Couldn't deserialize SaveGame. Creating new!");
                 save = new SaveGame();
             }
             file.Close();
 
             ints = StringToIntDict(save.ints);
             strings = StringToStringDict(save.strings);
 
             return true;
         }
         else
         {
             Debug.Log ("No Saves found.");
             return false;
         }
     }
 
     private void Save()
     {
         if (Application.isWebPlayer)
         {
             // Everything is in PlayerPrefs and doesn't have to written to file
             Debug.LogWarning("This is a WebPlayer! I shouldn't even be called!");
         }
         else
         {
             // Save dictionaries
             save.strings = StringDictToString(strings);
             save.ints = IntDictToString(ints);
 
             // Write to file
             FileStream file = File.Create(Application.persistentDataPath + "/" + fileName);
             formatter.Serialize(file, save);
             file.Close();
         }
     }
 
     public void Reset()
     {
         if (Application.isWebPlayer)
         {
             PlayerPrefs.DeleteAll();
             Debug.Log("Deleted PlayerPrefs");
         }
         else
         {
             ints.Clear();
             strings.Clear();
 
             save = new SaveGame();
 
             Debug.Log("Reset SaveGame");
         }
     }
     
     private void LateUpdate()
     {
         if(writeSave)
         {
             Save();
             writeSave = false;
         }
     }
 
     public void SetString(string id, string value)
     {
         if (Application.isWebPlayer)
         {
             PlayerPrefs.SetString(id, value);
         }
         else
         {
             strings[id] = value;
             writeSave = true;
         }
     }
 
     public string GetString(string id)
     {
         if (Application.isWebPlayer)
         {
             return PlayerPrefs.HasKey(id) ? PlayerPrefs.GetString(id) : "";
         }
         else
         {
             return strings.ContainsKey(id) ? strings[id] : "";
         }
     }
 
     public void SetInt(string id, int value)
     {
         if (Application.isWebPlayer)
         {
             PlayerPrefs.SetInt(id, value);
         }
         else
         {
             ints[id] = value;
             writeSave = true;
         }
     }
 
     public int GetInt(string id)
     {
         if (Application.isWebPlayer)
         {
             return PlayerPrefs.HasKey(id) ? PlayerPrefs.GetInt(id) : 0;
         }
         else
         {
             return ints.ContainsKey(id) ? ints[id] : 0;
         }
     }
 
     private Dictionary<string, int> StringToIntDict(string s)
     {
         Dictionary<string, int> dict = new Dictionary<string, int>();
 
         if (s == null)
         {
             Debug.LogWarning("Could not create dictionary, because string is null!");
             return dict;
         }
 
         string[] tokens = s.Split(new char[] { ':', ',' }, StringSplitOptions.RemoveEmptyEntries);
 
         // Walk through each item
         for (int i = 0; i < tokens.Length; i += 2)
         {
             dict.Add(tokens[i], int.Parse(tokens[i + 1]));
         }
 
         //Debug.Log("Loaded " + dict.Count + " ints");
         return dict;
     }
 
     private Dictionary<string, string> StringToStringDict(string s)
     {
         Dictionary<string, string> dict = new Dictionary<string, string>();
 
         if (s == null)
         {
             Debug.LogWarning("Could not create dictionary, because string is null!");
             return dict;
         }
 
         string[] tokens = s.Split(new char[] { ':', ',' }, StringSplitOptions.RemoveEmptyEntries);
 
         // Walk through each item
         for (int i = 0; i < tokens.Length; i += 2)
         {
             dict.Add(tokens[i], tokens[i + 1]);
         }
 
         //Debug.Log("Loaded " + dict.Count + " strings");
         return dict;
     }
 
     private string IntDictToString(Dictionary<string, int> d)
     {
         string result = "";
         foreach (KeyValuePair<string, int> pair in d)
         {
             result += pair.Key + ":" + pair.Value + ",";
         }
         // Remove the final delimiter
         result = result.TrimEnd(',');
 
         return result;
     }
 
     private string StringDictToString(Dictionary<string, string> d)
     {
         string result = "";
         foreach (KeyValuePair<string, string> pair in d)
         {
             result += pair.Key + ":" + pair.Value + ",";
         }
         // Remove the final delimiter
         result = result.TrimEnd(',');
 
         return result;
     }
 }
 
 [Serializable]
 class SaveGame
 {
     public string strings = "";
     public string ints = "";
 }
Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Dioinecail · Feb 16, 2018 at 11:53 AM 0
Share

I wonder how would you tackle arrays of data using the dictionaries

avatar image
0

Answer by pacifistmaster · Aug 10, 2016 at 07:52 PM

THIS IS WHAT YOU SHOULD DO!!!

If you are modifying your fields : example :

//VERSION 1 [Serializable] class PlayerData { public int num1; public int num2; }

//VERSION 2 [Serializable] class PlayerData { public int num1; }

// You just need to delete the current file with the old Serialized Fieds, Add this to the Start() Method: //------------------------ void Start(){

     if (File.Exists(Application.persistentDataPath + "/playerInfo.dat"))
     {
         File.Delete(Application.persistentDataPath + "/playerInfo.dat");
         Debug.Log("Deleted");
     }
 }

And Once Deleted, just remove the previous code , ;) worked as charm for me!!! ,a

Comment
Add comment · Show 2 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image or113 · Feb 18, 2017 at 02:40 PM 2
Share

While this will work as a workaround in a development env, this is dangerous to use in production! You will delete the user's data (coins/level etc)

avatar image Bunny83 or113 · Feb 18, 2017 at 05:44 PM 1
Share

Right. And once more we have an example of "who needs to shout usually isn't right".

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

32 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Member variable not persistent 0 Answers

Like PlayerPrefs but clears when game starts 2 Answers

Question on Singleton Object / Hierarchy Relationship 0 Answers

Need a persistent unique id for gameobjects 11 Answers

When an object is DontDestroyOnLoad(), where can I put script that will run at the start of a new scene? 2 Answers


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges