Search Unity

Easy Save - The Complete Save & Load Asset for Unity

Discussion in 'Assets and Asset Store' started by joeltebbett, May 28, 2011.

  1. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    You need to go to Window > Easy Save 3 > Settings, where you'll find a setting called "Assemblies containing ES3Types". You should put the names of your assemblies in this list so that Easy Save knows to search these for ES3Types.

    All the best,
    Joel
     
    faolad likes this.
  2. mklasson

    mklasson

    Joined:
    Oct 30, 2018
    Posts:
    9
    Hi,

    I'm building an iOS app and everything works fine with Managed Stripping Level set to low. On medium or high though, ES3 throws this exception when trying to load my save data (which is in a custom class):

    TypeLoadException: ES3Type for primitive could not be found, and the type list is empty. Please contact Easy Save developers at http://www.moodkie.com/contact
    at ES3Internal.ES3TypeMgr.CreateES3Type (System.Type type, System.Boolean throwException) [0x00000] in <00000000000000000000000000000000>:0
    at ES3Internal.ES3TypeMgr.GetOrCreateES3Type (System.Type type, System.Boolean throwException) [0x00000] in <00000000000000000000000000000000>:0
    at ES3Writer.Write (System.Object value, ES3+ReferenceMode memberReferenceMode) [0x00000] in <00000000000000000000000000000000>:0
    at ES3Internal.ES3JSONWriter.StartWriteProperty (System.String name) [0x00000] in <00000000000000000000000000000000>:0
    at ES3Writer.Write[T] (System.String key, System.Object value) [0x00000] in <00000000000000000000000000000000>:0
    at ES3.Save[T] (System.String key, System.Object value) [0x00000] in <00000000000000000000000000000000>:0
    at Cfg.InitAnimiResults () [0x00000] in <00000000000000000000000000000000>:0
    at Cfg.Load () [0x00000] in <00000000000000000000000000000000>:0
    at System.Collections.Generic.Dictionary`2[TKey,TValue].System.Collections.IDictionary.Remove (System.Object key) [0x00000] in <00000000000000000000000000000000>:0
    at Sirenix.Serialization.EasyBaseFormatter`1[T].ReadDataEntry (T& value, System.String entryName, Sirenix.Serialization.EntryType entryType, Sirenix.Serialization.IDataReader reader) [0x00000] in <00000000000000000000000000000000>:0
    at Sirenix.Serialization.EasyBaseFormatter`1[T].ReadDataEntry (T& value, System.String entryName, Sirenix.Serialization.EntryType entryType, Sirenix.Serialization.IDataReader reader) [0x00000] in <00000000000000000000000000000000>:0
    at Sirenix.Serialization.EasyBaseFormatter`1[T].ReadDataEntry (T& value, System.String entryName, Sirenix.Serialization.EntryType entryType, Sirenix.Serialization.IDataReader reader) [0x00000] in <00000000000000000000000000000000>:0
    System.Collections.Generic.Dictionary`2:System.Collections.IDictionary.Remove(Object)
    Sirenix.Serialization.EasyBaseFormatter`1:ReadDataEntry(T&, String, EntryType, IDataReader)
    Sirenix.Serialization.EasyBaseFormatter`1:ReadDataEntry(T&, String, EntryType, IDataReader)
    Sirenix.Serialization.EasyBaseFormatter`1:ReadDataEntry(T&, String, EntryType, IDataReader)

    I tried going into Window->Easy Save 3->Types and clicking the "Create ES3Type Script" button for my savedata class, figuring maybe that would hinder the stripping of some vital component, but that didn't change anything.

    Do you have any clues as to what I could be doing wrong?

    This is using Unity 2019.1.5f1 and a few weeks old version of EasySave 3 (can I tell which one somehow?).

    Thanks,
    Mikael
     
  3. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi Mikael,

    It looks like the core ES3Types are being stripped. I recently created a version of Easy Save with all ES3Types explicitly marked to not be stripped. If you PM me your invoice number and email address, I'll send over this version.

    All the best,
    Joel
     
  4. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,032
    @joeltebbett , with the auto-save (of GOs and prefabs thing) how is auto-save triggered and where are the GOs and Prefabs saved to? Which file(s)?
     
  5. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    Auto Save is triggered based on what the Save Event and Load Event settings are set to in the Auto Save settings (Window > Easy Save 3 > Auto Save).

    By default data is saved to Unity's Application.persistentDataPath. The filename used can also be found in the Auto Save settings.

    All the best,
    Joel
     
    Duffer123 likes this.
  6. Duffer123

    Duffer123

    Joined:
    May 24, 2015
    Posts:
    1,032
    Excellent thanks
     
  7. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    598
    I'm trying to stop the creation of the Easy Save 3 Manager: It's being auto-created in my active scene very frequently.

    I changed the options of EasySave but it doesn't seem change anything. Am I doing something wrong?

    upload_2019-7-6_22-30-24.png
     
  8. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    Are you using the latest version of Easy Save? The latest version available on the Asset Store should resolve this issue.

    All the best,
    Joel
     
  9. FeastSC2

    FeastSC2

    Joined:
    Sep 30, 2016
    Posts:
    598
    I'll try the new version then. Every time I update the asset, all my settings in this window are gone by the way.

    Question 1:
    This is super minor but I'm curious what's the best way to load a value with the least amount of code:
    I'm loading saving/loading my values one by one. I want it this way to have total control on what I save, I created a little wrapper function for this: my goal is to both have the value and a bool that states if the key I'm looking for exists in the file. I wonder what's the fastest way to load a value...


    Code (CSharp):
    1.     public static T LoadIfExists<T>(string key, string filePath, out bool _exists)
    2.     {
    3.         var settings = new ES3Settings(filePath);
    4.         _exists = ES3.FileExists(key, settings);
    5.         return Load<T>(key, settings);
    6.     }

    Code (CSharp):
    1.         // method 1 : my way
    2.         var keys = ES3.LoadIfExists<Dictionary<Location, int>>(SaveName.Keys, _path, out var keysExists);
    3.         if (keysExists) Keys = keys;
    4.  
    5.         // method 2 : normal way?
    6.         var keys2exists = ES3.FileExists(SaveName.Keys, new ES3Settings(_path));
    7.         if (keys2exists)
    8.         {
    9.             Keys = ES3.Load<Dictionary<Location, int>>(SaveName.Keys, _path);
    10.         }
    Question 2:
    I'm saving frequently during the game whenever the player is playing; for example when he opens up a treasure chest or many other in-game events.
    I'm quite new to saving data in my game, is this something that's safe? I saw in your code some lines where you seem to use backup files. Does that mean that if a file is being written in when the player exits the game, no files will be corrupted?

    Thanks for the asset, it's easy to use :)
     
  10. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    Are you looking for whether the key exists or the file exists? You seem to be providing the key as the parameter to the FileExists method, rather than a filename. If you want to check whether the key exists in a file, use ES3.KeyExists instead. Aside from that, I can see no more efficient way of what you're doing.

    Easy Save writes to a temporary file, so this should account for when data is corrupted when written. However, this won't account for corruption which is out of Easy Save's control (for example, the file system becoming corrupt). If you want to make backups of files, you should use the ES3.CreateBackup and ES3.RestoreBackup methods.

    All the best,
    Joel
     
    FeastSC2 likes this.
  11. Michal_Stangel

    Michal_Stangel

    Joined:
    Apr 17, 2017
    Posts:
    27
    Hi Joel,

    Do you still working on a BSON formatter? Personally still don't need it at this moment, but I'm sure lot of people will appreciate it.
     
  12. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    We've currently had to prioritise other more requested features. However, there's a feature request you can vote on on our forums: https://moodkie.com/forum/viewtopic.php?f=14&t=1214&view=viewpoll

    We're also currently thinking about how we can do this while retaining the benefits of the structured data formats.

    All the best,
    Joel
     
  13. Koval331

    Koval331

    Joined:
    Feb 3, 2019
    Posts:
    104
    Hi Joel,

    I want to create a save system that saves ScriptableObjects by reference.

    I created two ScriptableObjects scripts. SOVar acts as a container for SOData. SOData holds alpha int variable:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. public class SOData : ScriptableObject
    7. {
    8.     public int alpha;
    9. }
    10.  
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. [CreateAssetMenu]
    6. public class SOVar : ScriptableObject
    7. {
    8.     public ScriptableObject value;
    9. }
    10.  
    I also created a script that saves those variables:

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Saver : MonoBehaviour
    6. {
    7.     public SOData so_data;
    8.     public SOVar so_var;
    9.  
    10.     [ContextMenu("SaveSOData")]
    11.     public void SaveSOData()
    12.     {
    13.         ES3.Save<SOData>(so_data.name, so_data);
    14.     }
    15.  
    16.     [ContextMenu("SaveSOVar")]
    17.     public void SaveSOVar()
    18.     {
    19.         ES3.Save<SOVar>(so_var.name, so_var);
    20.     }
    21.  
    22. }
    23.  
    I created two variables and set alpha to 7:

    upload_2019-8-12_14-38-59.png

    Then I saved so_var through script above. Then I changed the value of alpha in so_data from 7 to 3 and saved so_data. The problem is that in the resulting JSON below the changes to alpha are not reflected in so_var variable. In so_var the alpha is still set to 7, when it should be 3.

    upload_2019-8-12_14-44-28.png

    How do I make the changes to be reflected in so_var when I save the so_data variable? I suspect this has something to do with references, but I don't know how to implement it specifically.
     
  14. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    Please could you PM me a basic project which replicates this? Or even better, email me a link to one uploaded to something like WeTransfer using the contact form at moodkie.com/contact? Hopefully then I will be able to see what is happening.

    All the best,
    Joel
     
  15. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi @Koval331,

    Thanks for sending that over. Do you save your so_var variable after changing the value from 7 to 3? If what you said is true, you’re only saving the so_data variable after making that change, so the so_var key won’t be updated. So to answer your question, you need to save the so_var variable again.

    From what I can tell, this is currently what you are doing:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class TestSafe : MonoBehaviour
    4. {
    5.     public SOData so_data;
    6.     public SOVar so_var;
    7.  
    8.     public void Start()
    9.     {
    10.         SaveSOVar();
    11.         so_data.alpha = 3;
    12.         SaveSOData();
    13.         // We've not saved so_var after changing so_data,
    14.         // so the data inside the "so_var" key in the file will still be the same
    15.         // as when we saved it. The data in the so_var key
    16.         // will only change if we save something using that key.
    17.     }
    18.  
    19.     public void SaveSOData()
    20.     {
    21.         ES3.Save<SOData>(so_data.name, so_data);
    22.     }
    23.  
    24.     public void SaveSOVar()
    25.     {
    26.         ES3.Save<SOVar>(so_var.name, so_var);
    27.     }
    28.  
    29. }
    All the best,
    Joel
     
  16. Koval331

    Koval331

    Joined:
    Feb 3, 2019
    Posts:
    104
    Yes, you are completely right. I was just hoping that there is some functionality in Easy Save that takes care of all this stuff automatically. Anyway, thanks for the help!

    p.s. You can consider it as a feature request: The functionality that takes care about updating all the data in other keys in the cases that I described.
     
  17. luizventura

    luizventura

    Joined:
    May 3, 2019
    Posts:
    3
    Hi guys,

    I would appreciate if you help me with some questions before I buy this tool, to see if it really fits into my necessities:

    1) (Most important question) My entire game is inside a single scene, I would need to save information about a lot of objects (this information would be like status, position, etc)... is it possible to save this information in an easy way or I'll need to do the setup for every single object?

    2) Does it save everything in a single file? Like we see normally in the games that we usually play.

    Depending on the answers I can have more questions, but that's it for now.

    Thank you in advance for your help!
     
  18. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there,

    It is indeed possible to save this data in an easy way. There are quite a few different ways you could save your data, but generally the easiest way would be to use Auto Save. This will save all supported Components on the GameObject it's applied to.

    If you need more control, you can use scripting to do this. For example, a script like the following could be used to save specific Components on the GameObjects you put in the script's "toBeSaved" array.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class SaveMgr : MonoBehaviour
    5. {
    6.     public GameObject[] toBeSaved;
    7.     public string filename = "file.es3";
    8.  
    9.     public void OnApplicationQuit()
    10.     {
    11.         for(int i=0; i<toBeSaved.Length; i++)
    12.         {
    13.             ES3.Save<Transform>("transform"+i, go.transform, filename);
    14.             ES3.Save<MyComponent>("myComponent"+i, go.GetComponent<MyComponent>(), filename);
    15.             // Etc ...
    16.         }
    17.     }
    18.  
    19.     public void Start()
    20.     {
    21.         if(!ES3.FileExists(filename))
    22.             return;
    23.  
    24.         for(int i=0; i<toBeSaved.Length; i++)
    25.         {
    26.             ES3.LoadInto<GameObject>("transform"+i, go.transform, filename);
    27.             ES3.LoadInto<MyComponent>("myComponent"+i, go.GetComponent<MyComponent>(), filename);
    28.             // Etc ...
    29.         }
    30. }
    Data will indeed be written to the same file, if the same filename is specified. Writing to a key which already exists in that file will overwrite that key.

    I strongly recommend checking out our Docs and Guides, as most common questions are answered in there. This will then allow you to see how you could integrate Easy Save into your project.

    All the best,
    Joel
     
    luizventura likes this.
  19. luizventura

    luizventura

    Joined:
    May 3, 2019
    Posts:
    3
    Thank you, Joel.

    I'll have a look, it looks promising based on your answer.
     
    joeltebbett likes this.
  20. Koval331

    Koval331

    Joined:
    Feb 3, 2019
    Posts:
    104
    Hi Joel,

    I was trying to implement an encryption feature but I get the same mistake no matter what.

    bug.png

    I shared a link to the project in my email to moodkie.

    Thanks in advance for your help!
     
  21. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there, and thanks for sending the project over.

    I encountered no errors when running your code, which suggests that a save file already exists on your computer which contains unencrypted data. As Easy Save is expecting encrypted data when you go to overwrite it, it will throw a cryptographic exception.

    Going to Window > Easy Save 3 > Tools > Open Persistent Data Path and deleting the existing save data will fix this.

    All the best,
    Joel
     
  22. Koval331

    Koval331

    Joined:
    Feb 3, 2019
    Posts:
    104
    It worked, thanks!

    And one more thing, please. Just to double-check, can I only load Easy Save 3 folder (when I import the asset)? Will it work fine?

    Just want to be 100% sure.
     
  23. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    If you're just using Easy Save 3, you only need to import the Plugins/Easy Save 3/ folder

    All the best,
    Joel
     
    Koval331 likes this.
  24. luizventura

    luizventura

    Joined:
    May 3, 2019
    Posts:
    3
    Hi, just feedback.

    I bought it some days ago and I started to implement it, looking very good until now.
    Very nice tool, congrats.

    Just one remark, my player object has a box collider 2d with a material that I created to avoid friction... when I load this object the material is missing, I managed to fix it with code... but it's something that maybe you could have a look.

    Thanks!
     
  25. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    486
    Hi there, and thanks for the feedback, much appreciated!

    It's not possible for me to tell what is happening without further information. If you have time, would you be able to PM me a basic project or script which replicates this?

    If your material is created dynamically, it's not possible for Easy Save to tell it exists. However, you can use the following code to tell Easy Save that it exists (it's important that you do this every time you create your Material, and always use the same unique ID ):

    Code (CSharp):
    1. GameObject.Find("Easy Save 3 Manager").GetComponent<ES3ReferenceMgr>().Add(yourMaterial, 12345);
    All the best,
    Joel