Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Easy Save - The Complete Save Data & Serialization Asset

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

  1. SeerSucker69

    SeerSucker69

    Joined:
    Mar 6, 2021
    Posts:
    68
    Thanks for your prompt explanation.
     
  2. blackert

    blackert

    Joined:
    May 14, 2020
    Posts:
    3
    Hey,

    I have a problem where I am trying for some time to resolve but to no avail. I have a SaveSystem : MonoBehaviour with the following Awake method:

    Code (CSharp):
    1.     void Awake()
    2.     {
    3.         settings = new ES3Settings("SaveFile.es3", ES3.Location.Cache);
    4.         ES3.CacheFile(settings);
    5.         foreach (var key in ES3File.cachedFiles.Keys)
    6.             Debug.Log ("Key = " + key);
    7.         foreach (var val in ES3File.cachedFiles.Values)
    8.             Debug.Log ("Value = " + val + ", location: " + val.settings.location);
    9.     }
    and get this output:
    Code (CSharp):
    1. Key = SaveFile.es3
    2. Value = ES3File, location: File
    So, somehow, the cache is not loaded?
    I have a method for this function as follows:
    Code (CSharp):
    1.     public Vector3 LoadMarketplace(long nextBuyPrice, float itemPriceInflation, float inflationSlowdownFactor)
    2.     {
    3.         foreach (var key in ES3File.cachedFiles.Keys)
    4.             Debug.Log ("Key = " + key);
    5.         foreach (var val in ES3File.cachedFiles.Values)
    6.             Debug.Log ("Value = " + val + ", location: " + val.settings.location);
    7.         Debug.Log(ES3.Load("nextBuyPrice"));
    8.         Debug.Log("Loading marketplace: " + ES3.Load("nextBuyPrice", settings));
    9.         Debug.Log("settings: " + settings.path + ", " + settings.location);
    10.         return new Vector3
    11.         (
    12.             ES3.Load("nextBuyPrice", nextBuyPrice, settings),
    13.             ES3.Load("itemPriceInflation", itemPriceInflation, settings),
    14.             ES3.Load("inflationSlowdownFactor", inflationSlowdownFactor, settings)
    15.         );
    16.     }
    And the output is as follows:
    Code (CSharp):
    1. Key = SaveFile.es3
    2. Value = ES3File, location: Cache
    3. 8
    4. KeyNotFoundException: Key "nextBuyPrice" was not found in this ES3File. Use Load<T>(key, defaultValue) if you want to return a default value if the key does not exist.
    As you can see, the ES3.Load from file returns '8' meaning the save file has that value. However, that value is not loaded onto cache.

    This load operation is triggered from a Start of another MonoBehaviour, so I am sure the cache load should run before it.

    Another finding, if I have ES3.CacheFile(settings); in every load function, it works. But, if I need to load from file to read everything, what is the meaning of cache.


    I am sure there is something I'm missing here, any ideas?
     
  3. JoelAtMoodkie

    JoelAtMoodkie

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

    This indicates that the file is in the cache, otherwise it wouldn't output anything. Note that the ES3File class is intentionally undocumented as it is only used internally.

    Please could you replicate your issue in a script which I can drop into a new scene of a new project, including the code which saves your data.

    All the best,
    Joel
     
  4. MarkHelsinki

    MarkHelsinki

    Joined:
    Jul 14, 2021
    Posts:
    23
    FormatException: Expected '{' or "null", found ','.

    A save is made and game stopped and then started again, and the save loads fine, no errors. Game is stopped again, and the save loaded again, and this time it returns this error. No obvious error in the JSON formatting that I could see. Nothing reported in the IDE when inspecting the JSON file.
     
  5. MarkHelsinki

    MarkHelsinki

    Joined:
    Jul 14, 2021
    Posts:
    23
    As
    Just to follow-up on this. Creating the first save and then multiple runtime loading of that save works fine, during and after application close. However, as soon as a second save is made, this is when the subsequent load gives an error.

    These are my save and load functions:


    public void SavePrefabInstances()
    {
    ES3.Save("prefabInstances", prefabInstances);
    }

    public void LoadPrefabInstances()
    {
    prefabInstances = ES3.Load("prefabInstances", new List<GameObject>());
    }
     
  6. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    Hi there, and thanks for getting in contact.

    Unfortunately I'm not able to replicate this from what you've said. Please could you replicate this in a new project with a simple scene and private message it to me with instructions?

    All the best,
    Joel
     
  7. rerwandi

    rerwandi

    Joined:
    Dec 8, 2014
    Posts:
    544
    When i tried to use ES3.DeleteKey, the key is deleted in cache and after the cache is commited into file, the key still exist in the file even tho it's not exist anymore in the cache.

    I need to use ES3File.DeleteKey() and ES3File.Sync() to get what I want.
    Is it correct? How about the performance impact if in my game the player will use delete key a lot to remove unused information?

    Code (CSharp):
    1. public override Task DeleteKey(string key)
    2.         {
    3.             var settings = new ES3Settings("SaveFile.es3", ES3.Location.Cache);
    4.             ES3.DeleteKey(key, settings);
    5.            
    6.             var file = new ES3File("SaveFile.es3");
    7.             file.DeleteKey(key);
    8.             file.Sync();
    9.            
    10.             return Task.FromResult(1);
    11.         }
     

    Attached Files:

  8. JoelAtMoodkie

    JoelAtMoodkie

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

    You should not be using ES3File but instead using the Cache storage location as documented here:

    https://docs.moodkie.com/easy-save-3/es3-guides/performance/

    ES3File is intentionally undocumented as it's only used internally.

    When using caching the performance impact is negligible.

    All the best,
    Joel
     
  9. rerwandi

    rerwandi

    Joined:
    Dec 8, 2014
    Posts:
    544
    I'm using cache storage location, my problem is that I have key that already been saved in file, but later on i want to delete that key because it will make the filesize large with useless information.

    here is the flow
    I save "Object A" in a cache -> StoreCacheFile() run making "Object A" in save file -> Cache local file and load from it -> I delete "Object A" key in cache -> StoreCacheFile() again but the key is still in the save file as it's not overwriting all the content with current state but rather write update it if the key found, and add it if it's not. But doesn't delete unused key in the file.

    that's why i use ES3File to manually delete the unused key in the file
     
  10. JoelAtMoodkie

    JoelAtMoodkie

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

    I don't appear to be encountering any issues on Easy Save 3.5.3 or 3.5.4. Are you using the latest version of Easy Save?

    I tested using the following script:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class DeleteFromCache : MonoBehaviour
    4. {
    5.     void Start()
    6.     {
    7.         // Ensure there's no existing save data before we run the test.
    8.         ES3.DeleteFile();
    9.  
    10.         var settings = new ES3Settings(ES3.Location.Cache);
    11.         ES3.Save("key1", 123, settings);
    12.         ES3.Save("key2", 456, settings);
    13.         ES3.Save("key3", 789, settings);
    14.  
    15.         Debug.Assert(ES3.KeyExists("key2", settings));
    16.         Debug.Assert(!ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    17.  
    18.         ES3.StoreCachedFile();
    19.  
    20.         Debug.Assert(ES3.KeyExists("key2", settings));
    21.         Debug.Assert(ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    22.  
    23.         ES3.DeleteKey("key2", settings);
    24.  
    25.         Debug.Assert(!ES3.KeyExists("key2", settings));
    26.         Debug.Assert(ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    27.  
    28.         ES3.StoreCachedFile();
    29.  
    30.         Debug.Assert(!ES3.KeyExists("key2", settings));
    31.         Debug.Assert(!ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    32.  
    33.         Debug.Log("Finished");
    34.     }
    35. }
    All the best,
    Joel
     
  11. stevenatunity

    stevenatunity

    Joined:
    Apr 17, 2015
    Posts:
    114
    Hi Joel,
    Is it possible to read Easy Save 2 data in a text editor?
    Thank,
    Steven
     
    Last edited: Feb 7, 2023
  12. rerwandi

    rerwandi

    Joined:
    Dec 8, 2014
    Posts:
    544
    I'm using the latest 3.5.4 and this test still gave me error.
    I tried this and it still doesnt delete key in file.
    This my current savefile
    Code (CSharp):
    1. {
    2.     "key1" : {
    3.         "__type" : "int",
    4.         "value" : 123
    5.     },
    6.     "key3" : {
    7.         "__type" : "int",
    8.         "value" : 789
    9.     },
    10.     "key2" : {
    11.         "__type" : "int",
    12.         "value" : 456
    13.     }
    14. }
    this is the test script
    Code (CSharp):
    1.  
    2. void Start()
    3. {
    4.     ES3.CacheFile();
    5.     var settings = new ES3Settings(ES3.Location.Cache);
    6.  
    7.     Debug.Assert(ES3.KeyExists("key2", settings));
    8.     Debug.Assert(ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    9.  
    10.     ES3.DeleteKey("key2", settings);
    11.  
    12.     Debug.Assert(!ES3.KeyExists("key2", settings));
    13.     Debug.Assert(ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    14.  
    15.     ES3.StoreCachedFile();
    16.  
    17.     Debug.Assert(!ES3.KeyExists("key2", settings));
    18.     Debug.Assert(!ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));
    19.  
    20.     Debug.Log("Finished");
    21. }
    22.  
    Assertion failed in this line
    Debug.Assert(!ES3.KeyExists("key2", new ES3Settings(ES3.Location.File)));

    the "key2" is still in the file even after we run DeleteKey() then StoreCachedFile()

    I think the difference with your test is that I use ES3.CacheFile() to load current savefile into the cache first
     
    Last edited: Feb 7, 2023
  13. JoelAtMoodkie

    JoelAtMoodkie

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

    It's possible with Easy Save 3, but not Easy Save 2.

    All the best,
    Joel
     
    stevenatunity likes this.
  14. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    Thanks for sending that over, that was indeed what was preventing me from being able to replicate.

    This is an easy fix at our end. If you private message me your invoice number I'll send over an update which resolves this.

    All the best,
    Joel
     
  15. bsarsgard

    bsarsgard

    Joined:
    Apr 2, 2013
    Posts:
    1
    Has anyone had success saving Nullable types? Whenever I try to load a file with a Nullable<Int32> (int?), I get the following error:
    NotSupportedException: Cannot create an instance of System.Nullable`1[System.Int32]. However, you may be able to add support for it using a custom ES3Type file. For more information see: http://docs.moodkie.com/easy-save-3/es3-guides/controlling-serialization-using-es3types/

    I can't figure out how to add a custom type for this though. I tried writing one manually for Nullable<Int32> but it doesn't seem to get picked up.
     
  16. JoelAtMoodkie

    JoelAtMoodkie

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

    I was able to add support for Nullable<int> by adding the following ES3Type to the Assets/Easy Save 3/Types/ folder:

    Code (CSharp):
    1. using System;
    2.  
    3. namespace ES3Types
    4. {
    5.     [UnityEngine.Scripting.Preserve]
    6.     public class ES3UserType_NullableInt : ES3Type
    7.     {
    8.         public static ES3Type Instance = null;
    9.  
    10.         public ES3UserType_NullableInt() : base(typeof(Nullable<int>)){ Instance = this; priority = 1; }
    11.  
    12.         public override void Write(object obj, ES3Writer writer)
    13.         {
    14.             var instance = (Nullable<int>)obj;
    15.             writer.WriteProperty("HasValue", instance.HasValue);
    16.             if(instance.HasValue)
    17.                 writer.WriteProperty("Value", instance.Value);
    18.         }
    19.  
    20.         public override object Read<T>(ES3Reader reader)
    21.         {
    22.             if(reader.ReadProperty<bool>())
    23.                 return new Nullable<int>(reader.ReadProperty<int>());
    24.             return new Nullable<int>();
    25.         }
    26.     }
    27. }
    And tested saving an array of them using this script:

    Code (CSharp):
    1. using UnityEngine;
    2. using System;
    3.  
    4. public class SaveLoadNullableInt : MonoBehaviour
    5. {
    6.     // Start is called before the first frame update
    7.     void Start()
    8.     {
    9.         var nullableInts = new Nullable<int>[] { new Nullable<int>(3), new Nullable<int>(), new Nullable<int>(0) };
    10.      
    11.         ES3.Save("nullableInts", nullableInts);
    12.         var loadedNullableInts = ES3.Load<Nullable<int>[]>("nullableInts");
    13.  
    14.         foreach (var nullableInt in loadedNullableInts)
    15.             Debug.Log(nullableInt.HasValue ? nullableInt.Value.ToString() : "null");
    16.     }
    17. }
    Note that I recommend deleting your existing save data in case it's corrupted with your previous attempts (Tools > Easy Save 3 > Clear Persistent Data Path).

    All the best,
    Joel
     
  17. CrandellWS

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    178
    So i am wanting my spreadsheet data encrypted on the device so I enable the encryption option in the Runtime settings. then I sync the data to the cloud and the data is not encrypted and saved as mentioned here: https://forum.unity.com/threads/eas...erialization-asset.91040/page-28#post-6426524

    This is fine for the moment as it is easier to work with the plain text in the database upfront. Later I will want to encrypt it there as well but my question is about not hashing the username. I tracked the code down to lines 88-89 in ES3WebClass.cs

    Code (CSharp):
    1.  
    2. #if !DISABLE_ENCRYPTION && !DISABLE_HASHING
    3.             user = ES3Internal.ES3Hash.SHA1Hash(user);
    4. #endif
    5.  
    i was thinking is there a better way to disable this as I want the username plain-text for working with an existing application and the option i thought was to add a new scripting define symbol and use it but this is not ideal for updates with ES3.

    I have tried to disable the encryption in the runtime settings but then I can not seem to encrypt anything even when using code settings to try to enable it like this


    Code (CSharp):
    1.  
    2.             var settings = new ES3Settings(ES3.EncryptionType.AES, "myPassword");
    3.             settings.location = ES3.Location.File;
    4.  
    anyway for the moment I really want the device spreadsheet file encrypted and the cloud sync username plaintext and any help to this end is appreciated. Additional guidance towards best way to encrypt the spreadsheet in the database as well is also welcomed but bare in mind I will want to decrypt it outside of the unity app at later times using Php.

    Thanks for this useful and easy to use asset.

    and just in case here is the code used to sync to the cloud database table.


    Code (CSharp):
    1.  
    2.             var settings = new ES3Settings(ES3.EncryptionType.AES, "myPassword");
    3.             settings.location = ES3.Location.File;
    4.      
    5.             // Create a new ES3Cloud object with the URL to our ES3.php file.
    6.             var cloud = new ES3Cloud("http://192.168.8.110/NITRO/cloud/ES3Cloud.php", "API_KEY");
    7.  
    8.             // Synchronise a local file with the cloud for a particular user.
    9.             string username = GetUsername();
    10.  
    11.             yield return StartCoroutine(cloud.Sync(filePath, username, "myPassword", settings));
    12.  
     
    Last edited: Feb 26, 2023
  18. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    Hi there,
    At the moment to disable hashing of the username you should set the DISABLE_HASHING in Edit > Project Settings > Player > Scripting Define Symbols. This will disable hashing but not encryption, and the platform defines are entirely independent of the encryption setting in Tools > Easy Save 3 > Settings. If you wanted to set this conditionally you would need to use Unity's API for modifying the scripting define symbols. For example, PlayerSettings.SetScriptingDefineSymbolsForGroup.

    The encryption is only intended to be decrypted from Unity using Easy Save, so I'm afraid I wouldn't be able to assist with this. Doing so would be non-trivial because the encryption is buffered, and I don't believe PHP has the required APIs in order to decrypted AES-encrypted data in this way.

    All the best,
    Joel
     
    CrandellWS likes this.
  19. moayad-jawaker

    moayad-jawaker

    Joined:
    Mar 4, 2020
    Posts:
    10
    @JoelAtMoodkie Hello, we are using ES3 version 3.5.1 and we got an exception on some users regarding the encryption and it is disabled in the settings.

    [02/27/2023 19:07:12] <Exception>: FormatException: Cannot load from file because the data in it is not JSON data, or the data is encrypted.
    If the save data is encrypted, please ensure that encryption is enabled when you load, and that you are using the same password used to encrypt the data.

    so any idea what is the problem?
     

    Attached Files:

  20. JoelAtMoodkie

    JoelAtMoodkie

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

    The FormatException is thrown if Easy Save encounters data which isn't JSON formatted, not just an issue relating to encryption (see the Error Handling section of the docs). This can also happen if the file has been tampered with, either by the user or an external piece of software, meaning the data is no longer valid JSON.

    For example if a piece of antivirus software decides that the file could be insecure, it will usually replace the contents of the file with empty bytes. In this case you would need to advise the user to allow the file in their antivirus software as this is not something you can prevent otherwise.

    Another situation is if the user tries to open the file in a text editor and then resaves it with a different encoding, meaning the data is no longer UTF8 encoded.

    In your case the error has occurred at the very beginning of the file, indicating that the file does not begin with an opening brace (or whitespace preceding an opening brace), meaning the data is not valid JSON. You can try outputting the contents of the file using ES3.LoadRawString to see what the contents are to see if this helps you understand.

    As you're on quite an older version of Easy Save I also recommend updating in case it relates to any issue which has since been resolved.

    All the best,
    Joel
     
    Last edited: Feb 28, 2023
  21. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    hi iam using this script to save the Player position but when I go back to the main menu I doesn't work


    this the save script

    sing UnityEngine;
    using UnityEngine.SceneManagement;


    public class SavePosition : MonoBehaviour
    {

    public GameObject player;
    public Collider trigger;

    private void OnTriggerEnter(Collider other)
    {
    if (other.gameObject == player)
    {
    Vector3 position = player.transform.position;
    string sceneName = SceneManager.GetActiveScene().name;

    ES3.Save<Vector3>("playerPosition", position, "SaveData/game.es3");
    ES3.Save<string>("Level0", sceneName, "SaveData/game.es3");

    Debug.Log("Player position saved in scene " + sceneName + "!");
    }
    }
    }


    and this is the load script


    ublic class LoadPosition : MonoBehaviour
    {

    public GameObject player;
    public Button loadButton;

    private void Start()
    {
    loadButton.onClick.AddListener(LoadPlayerPosition);
    }

    private void LoadPlayerPosition()
    {
    if (ES3.FileExists("SaveData/game.es3"))
    {
    string sceneName = ES3.Load<string>("Level0", "SaveData/game.es3");
    Vector3 position = ES3.Load<Vector3>("playerPosition", "SaveData/game.es3");

    player.transform.position = position;
    SceneManager.LoadScene(sceneName);

    Debug.Log("Player position and scene loaded!");
    }
    else
    {
    Debug.Log("No saved player position and scene found.");
    }
    }
    }
     
  22. CrandellWS

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    178
    thanks I feel silly not realizing I should just DISABLE_HASHING :oops:
     
  23. JoelAtMoodkie

    JoelAtMoodkie

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

    You appear to be loading your position, but then loading a new scene. Unless you've marked your player as DontDestroyOnLoad, this object will no longer exist after you load the new scene. In this case you would need a separate script in the scene you're loading to load the position after the scene has loaded.

    Otherwise your scripts appear to be working fine for me.

    All the best,
    Joel
     
  24. CrandellWS

    CrandellWS

    Joined:
    Oct 31, 2015
    Posts:
    178
  25. JoelAtMoodkie

    JoelAtMoodkie

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

    Edit: Ignore my previous response, I was getting confused.

    You use ES3Cloud.RenameFile in the same way you use the other ES3Cloud methods. I.e.

    Code (CSharp):
    1. // Create a new ES3Cloud object with the URL to our ES3.php file.
    2. var cloud = new ES3Cloud("https://www.myserver.com/ES3Cloud.php", "myAPIKey");
    3.  
    4. // Rename the file.
    5. yield return StartCoroutine(cloud.RenameFile("oldFilename.es3", "newFilename.es3", "myUser", "myUsersPassword"));
    6.  
    7. if(cloud.isError)
    8.     Debug.LogError(cloud.error);
    It looks like it wasn't previously showing up in the list on the ES3Cloud page, but I've fixed that and you can now navigate to it here:

    https://docs.moodkie.com/easy-save-3/es3-api/es3-methods/es3cloud-renamefile/

    All the best,
    Joel
     
    Last edited: Mar 6, 2023
    CrandellWS likes this.
  26. fengwangzi

    fengwangzi

    Joined:
    Jan 25, 2020
    Posts:
    8
    when I use save
    Sometimes it will report an error
    IOException: Sharing violation on path G:\XXXXX
    ES3Internal.ES3Stream.CreateStream (ES3Settings settings, ES3Internal.ES3FileMode fileMode) (at Assets/Plugins/Easy Save 3/Scripts/Streams/ES3Stream.cs:69)
    ES3Reader.Create (ES3Settings settings) (at Assets/Plugins/Easy Save 3/Scripts/Readers/ES3Reader.cs:346)

    and then continue to use it correctly, what is going on? What do I have to do to solve this problem.
     
  27. zKici

    zKici

    Joined:
    Feb 12, 2014
    Posts:
    438
    Sounds like something else is already into that file, likely can't have 2 things opening the file at the same time
     
    JoelAtMoodkie likes this.
  28. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    Exactly as zKici suggests, this error occurs because another application or thread has the file open, preventing other applications from accessing it.

    All the best,
    Joel
     
  29. fengwangzi

    fengwangzi

    Joined:
    Jan 25, 2020
    Posts:
    8
    Oh, there may be something wrong with the code I wrote that prevents it from saving.
     
    Last edited: Mar 17, 2023
  30. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    It could be that cloud or anti-virus software is accessing the file, not necessarily that you opened it in an application yourself.

    The only other way to trigger the error would be if you're attempting to use Easy Save from multiple threads at the same time.

    All the best,
    Joel
     
  31. fengwangzi

    fengwangzi

    Joined:
    Jan 25, 2020
    Posts:
    8
    You are the fastest developer I've seen answer questions, very surprised, and for so many years. Thank you very much, there may be a problem with the data I stored that caused the error.
    I wish you all the best.
    Very much admire you.
     
    JoelAtMoodkie likes this.
  32. fengwangzi

    fengwangzi

    Joined:
    Jan 25, 2020
    Posts:
    8
    I want to know when I read the data, do I need to determine in advance for each one myself whether it exists or not?
    Or can I just LOAD.
    Is there a judgment in the program by default?
     
  33. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    This is covered in the Getting Started guide:
    Code (CSharp):
    1. ES3.Save("myInt", 123);
    2. myInt = ES3.Load<int>("myInt", defaultValue);
    Code (CSharp):
    1. if(ES3.KeyExists("myInt"))
    2.     myInt = ES3.Load<int>("myInt");
    All the best,
    Joel
     
    CrandellWS and fengwangzi like this.
  34. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    I have question the work on the he save the position of the character everything work on on the editor but when I compiled and run the game in Xcode the Load doesn't work how I fix this in the Settings or the Script ?
     
  35. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    Hi there. Please could you show me the script?
     
  36. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    ok this are this script

    LOAD SCRIPT

    using UnityEngine;
    using UnityEngine.SceneManagement;


    public class LoadPlayerPosition : MonoBehaviour
    {
    public string saveFileName = "playerPosition.es3";
    public string gameSceneName = "Level0";
    public ES3Settings saveSettings;

    private string GetFullPath(string fileName)
    {
    return System.IO.Path.Combine(saveSettings.path, fileName);
    }

    public void LoadPositionAndSwitchScene()
    {
    string filePath = GetFullPath(saveFileName);
    Debug.Log("File Path: " + filePath);

    if (ES3.FileExists(saveFileName, saveSettings))
    {
    Vector3 loadedPosition = ES3.Load<Vector3>("playerPosition", saveFileName, saveSettings);
    PlayerPrefs.SetFloat("LoadedPlayerPositionX", loadedPosition.x);
    PlayerPrefs.SetFloat("LoadedPlayerPositionY", loadedPosition.y);
    PlayerPrefs.SetFloat("LoadedPlayerPositionZ", loadedPosition.z);
    PlayerPrefs.SetInt("LoadPlayerPosition", 1);
    SceneManager.LoadScene(gameSceneName);
    }
    else
    {
    Debug.LogWarning("Save file not found.");
    }
    }
    }

    THE SAVE SCRIPT

    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.UI;


    public class SaveLoad : MonoBehaviour
    {

    public GameObject player;
    public Collider trigger;
    public Button loadButton;

    private void Start()
    {
    loadButton.onClick.AddListener(LoadPlayerPosition);
    }

    private void OnTriggerEnter(Collider other)
    {
    if (other.gameObject == player)
    {
    Vector3 position = player.transform.position;
    string sceneName = SceneManager.GetActiveScene().name;

    ES3.Save<Vector3>("playerPosition", position, "SaveData/game.es3");
    ES3.Save<string>("Level0", sceneName, "SaveData/game.es3");

    Debug.Log("Player position saved in scene " + sceneName + "!");
    }
    }

    private void LoadPlayerPosition()
    {
    if (ES3.FileExists("SaveData/game.es3"))
    {
    string sceneName = ES3.Load<string>("sceneName", "SaveData/game.es3");
    Vector3 position = ES3.Load<Vector3>("playerPosition", "SaveData/game.es3");

    player.transform.position = position;
    SceneManager.LoadScene(sceneName);

    Debug.Log("Player position and scene loaded!");
    }
    else
    {
    Debug.Log("No saved player position and scene found.");
    }
    }
    }
     
  37. JoelAtMoodkie

    JoelAtMoodkie

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

    I tried to replicate this but your code doesn't work in the Editor, so this might not be an iOS specific issue. In particular you're specifying a different filename/path in SaveLoad than in LoadPlayerPosition.

    I recommend deleting your save data in the Editor (Tools > Easy Save 3 > Clear Persistent Data Path) and see if this replicates the issue in the Editor.

    All the best,
    Joel
     
  38. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    upload_2023-3-25_17-48-50.png
    I got this error
     
  39. JoelAtMoodkie

    JoelAtMoodkie

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

    This code is coming from your code rather than ours. It's likely because you're using settings.path, but your settings object doesn't specify a path so it's null. In this case you should use settings.FullPath, which returns the path to the default file.

    All the best,
    Joel
     
  40. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    ok will try that
     
  41. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    he working now well but I got and issue when I go to next level load the correct level but not the right position this are the setting on the level
    And this is the load script :
    using UnityEngine;
    using UnityEngine.SceneManagement;
    using UnityEngine.IO;

    public class LoadPosition : MonoBehaviour
    {
    public string saveFileName = "CharacterPosition";
    public GameObject player;

    private void Start()
    {
    SceneManager.sceneLoaded += OnSceneLoaded;
    }

    private void OnDestroy()
    {
    SceneManager.sceneLoaded -= OnSceneLoaded;
    }



    public void LoadAndStartGame()
    {
    if (ES3.FileExists(saveFileName))
    {
    int currentLevel = ES3.Load<int>("currentLevel", saveFileName);
    SceneManager.LoadScene("Level" + currentLevel);
    }
    else
    {
    Debug.LogError("Save file doesn't exist.");
    }
    }


    public void StartNewGame()
    {
    // Load the first level (assuming it's named "Level0").
    SceneManager.LoadScene("Level1");

    // Delete the save file if it exists.
    if (ES3.FileExists(saveFileName))
    {
    ES3.DeleteFile(saveFileName);
    Debug.Log("Deleted save file: " + saveFileName);
    }
    }

    private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
    {
    if (ES3.FileExists(saveFileName))
    {
    Vector3 position = ES3.Load<Vector3>("position", saveFileName);
    Quaternion rotation = ES3.Load<Quaternion>("rotation", saveFileName);

    player.transform.position = position;
    player.transform.rotation = rotation;

    Debug.Log("Loaded position and level: " + saveFileName);
    }
    else
    {
    Debug.LogWarning("No save file found. Starting from the default position.");
    }
    }

    }
     

    Attached Files:

  42. JoelAtMoodkie

    JoelAtMoodkie

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

    Please could you show me the code you're using to save.

    Please could you also put a Debug.Log call immediately before your ES3.Load call and ensure that it's being called.

    All the best,
    Joel
     
  43. dragonstar

    dragonstar

    Joined:
    Sep 27, 2010
    Posts:
    222
    this is the code

    using UnityEngine;
    using UnityEngine.IO;
    using UnityEngine.SceneManagement;

    public class SavePosition : MonoBehaviour
    {
    public string saveFileName = "CharacterPosition";
    public GameObject player;

    private void OnTriggerEnter(Collider other)
    {
    if (other.gameObject == player)
    {
    Save();
    }
    }

    public void Save()
    {
    ES3.Save<int>("currentLevel", GameManager.Instance.currentLevel, saveFileName);
    ES3.Save<Vector3>("position", player.transform.position, saveFileName);
    ES3.Save<Quaternion>("rotation", player.transform.rotation, saveFileName);

    Debug.Log("Saved position and level: " + saveFileName);
    }
    }
     
  44. JoelAtMoodkie

    JoelAtMoodkie

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

    Did you try putting Debug.Log calls before your Load calls? I tried replicating this at my end and Load isn't called because Start() is called after Scene manager.sceneLoaded (this is unrelated to Easy Save).

    All the best,
    Joel
     
  45. ZolnierGames

    ZolnierGames

    Joined:
    Feb 19, 2018
    Posts:
    88
    So, if I have a class list as follows with about 100 rows, how do I save the whole list?

    public class TeamClass
    {
    public int TeamID { get; set; }
    public string TeamName { get; set; }
    }

    List<TeamClass> GameTeams= new List<TeamClass>();

    And then in my game, I have about 100 teams in that GameTeams list... How do I save the whole thing with ES3?

    Thanks!
     
  46. JoelAtMoodkie

    JoelAtMoodkie

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

    As your TeamClass contains properties you would first need to add the [ES3Serializable] attribute to them (see https://docs.moodkie.com/easy-save-3/es3-guides/choosing-what-is-saved/).

    Once you've done this you can simply save the Lists as described in the Getting Started guide:
    https://docs.moodkie.com/easy-save-3/getting-started/#saving-and-loading-collections

    For example:

    Code (CSharp):
    1. ES3.Save("myList", myList);
    2. myList = ES3.Load("myList", defaultValue);
    All the best,
    Joel
     
  47. ZolnierGames

    ZolnierGames

    Joined:
    Feb 19, 2018
    Posts:
    88
    So, it appears I am still doing something wrong. I believe I am declaring everything properly:
    I declare my class list at the beginning of my script:
    [ES3Serializable]
    List<DZ.GameTeamClass> ExportTeams;

    And then when I try to use sqlite to query my database and get the teams, the list populates just fine...
    ExportTeams = DZ.control.SqlDB.Query<DZ.GameTeamClass>("select * from GameTeams order by TeamID");
    ES3.Save("GameTeams", ExportTeams);

    But when I save via ES3, the save file is basically empty:

    {
    "GameTeams" : {
    "__type" : "System.Collections.Generic.List`1[[DZ+GameTeamClass, Assembly-CSharp, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null]],mscorlib",
    "value" : [
    {
    }
    ]
    }
    }

    What am I doing wrong?
     
  48. JoelAtMoodkie

    JoelAtMoodkie

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

    This is likely because the fields or properties of your GameTeamClass aren't serializable. See https://docs.moodkie.com/easy-save-3/es3-guides/es3-supported-types/

    If this isn't the issue, please could you post your GameTeamClass so I can try to replicate this at my end.
     
  49. ZolnierGames

    ZolnierGames

    Joined:
    Feb 19, 2018
    Posts:
    88
    So, in order for this to work, I can't declare the whole class via [ES3Serializable] as follows?

    [ES3Serializable]
    public class ExportTeamClass
    {
    public int TeamID { get; set; }
    public string TeamName { get; set; }
    public string Abbrev { get; set; }
    public int ConfID { get; set; }
    public byte R1 { get; set; }
    public byte G1 { get; set; }
    public byte B1 { get; set; }
    public byte R2 { get; set; }
    public byte G2 { get; set; }
    public byte B2 { get; set; }
    }

    But rather, I have to declare each variable inside the class specifically like so?

    public class ExportTeamClass
    {
    [ES3Serializable]
    public int TeamID { get; set; }
    [ES3Serializable]
    public string TeamName { get; set; }
    [ES3Serializable]
    public string Abbrev { get; set; }
    [ES3Serializable]
    public int ConfID { get; set; }
    [ES3Serializable]
    public byte R1 { get; set; }
    [ES3Serializable]
    public byte G1 { get; set; }
    [ES3Serializable]
    public byte B1 { get; set; }
    [ES3Serializable]
    public byte R2 { get; set; }
    [ES3Serializable]
    public byte G2 { get; set; }
    [ES3Serializable]
    public byte B2 { get; set; }
    }
     
  50. JoelAtMoodkie

    JoelAtMoodkie

    Joined:
    Oct 18, 2009
    Posts:
    912
    That's correct, because all of your members are properties, not fields, so are not automatically supported.

    To clarify the ES3Serializable attribute is to indicate that a member is serializable, so adding it above a class won't do anything. For more information please see the appropriate guide:
    https://docs.moodkie.com/easy-save-3/es3-guides/choosing-what-is-saved/