Search Unity

Easy Save - The Complete Save & Load Asset for Unity

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

  1. Izitmee

    Izitmee

    Joined:
    Jan 27, 2011
    Posts:
    3,228
    Though I'd mention that I'm using EasySave 2 on Android, to save a Dictionary<int,int> and a List<int> each composed of some 30 elements in PlayerPrefs. I'm testing it on an HTC Desire (from a couple years ago), and it's working perfectly: very fast, reliable, and a breeze to use :)
     
  2. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Thanks for the encouragement! Providing support is one of my favourite aspects of software development, which is probably why our standards are so high :)

    We've got some more plugins in the pipeline, but for the time being we're going to concentrate on getting all of the suggestions for Easy Save 2 implemented.
     
  3. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    There are a few small optimisations we've yet to make, so expect future releases to be even faster :)
     
  4. Mark_T

    Mark_T

    Joined:
    Apr 25, 2011
    Posts:
    303
    Congrats for releasing v.2 for EasySave :)
    I`m happy to see that you`re so exigent and I have to say that I`m really looking forward to see the final version as a Playmaker action.
    All the best.
     
  5. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Don't worry Mark, we've not forgotten about you :D
     
  6. donzen

    donzen

    Joined:
    Oct 24, 2009
    Posts:
    54
    Hi joeltebbett,
    nice work on EasySave! it's really useful and easy to use.
    One noob question: it's fully working if I save data and load it later, but what if I need to load data at the start of the game? where should the files be located? I tried different paths, but I'm getting a little bit confused...
    I'm working on iOS, so I need to keep the file somewhere and load them at runtime.
     
  7. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi donzen,
    The saved data is persistent, so it'll still be there when you close the game. For example, if you do:
    Code (csharp):
    1. ES2.Save(42, "myFile.txt");
    Then close the app, open it up again and call this:
    Code (csharp):
    1. int myData = ES2.Load<int>("myFile.txt");
    myData will equal 42, unless you delete the data somewhere between calling ES2.Save and ES2.Load.

    Regards,
    Joel
     
  8. donzen

    donzen

    Joined:
    Oct 24, 2009
    Posts:
    54
    hi Joel,
    maybe you misunderstood my question.

    Imagine a complete new game, starting for the first time: there is no saved data yet. I need to load some data into the game from some files for the first time (no previous saves, I only have some .txt files to load from). How can it be done? Where should these initial files be located to be successfully loaded?

    Normally, the process would be: Start the game -> Play (and generate some data) -> Save this data to a file -> Load the saved data later.
    What I need is: Start the game -> Load some data from files -> Play the game -> Save some new data -> Load whatever later

    Thanks.
     
  9. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    I understand now. If you didn't know already, by default it will save to PlayerPrefs, and not to File. Presuming you are saving to File (by providing an ES2Settings with saveLocation set to ES2.SaveLocation.File, or by using the '&savelocation=file' parameter in the filename), the default save directory is the same as Application.persistentDataPath. However, this path is created when the app is installed, so you can't add files here prior to runtime.

    The way around this is to import the files into Unity as TextAssets, using a .bytes extension. The next update for ES2 will support saving of TextAssets and should be with us in the next week. With this, you would do the following:

    Code (csharp):
    1. // To save a Text Asset named myTextAsset.bytes to a file named mySaveFile.ext
    2. ES2.Save(Resources.Load("myTextAsset.bytes") as TextAsset, "mySaveFile.ext");
    Regards,
    Joel
     
  10. Izitmee

    Izitmee

    Joined:
    Jan 27, 2011
    Posts:
    3,228
    Awesome!!!! EasySave 2 looks more wonderful with each day :)
     
  11. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    I'm going to try and get another update to ES2 on the Asset Store tomorrow. Apologies if I don't get it sent to Caitlyn in time!

    In this update:
    • Low Memory Mode
    • PlayMaker Actions
    • Saving Text Assets
    • Saving Raw Bytes
    • Ability to change default settings

    This should be the last update before it comes out of beta as it has been thoroughly tested, and we've had some great feedback from everyone. We've got enough feature requests to last us until the end of time, so there will be regular updates for at least the next few months :)
     
  12. Mark_T

    Mark_T

    Joined:
    Apr 25, 2011
    Posts:
    303
    Wow, great news!!
    Really looking forward to the Playmaker version.
    Again, many thanks. :)
     
  13. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Not a problem Mark! We'd love to get your feedback on it when you get a chance, so if there's any improvements you would like made to it, let me know :)
     
  14. mrbdrm

    mrbdrm

    Joined:
    Mar 22, 2009
    Posts:
    510
    Hi
    i bought your great assest and i looked at the docs but i didnt find a complete example of how to save and load a game ( with any save data type )
    im not a very good programer and i work on my project alone i know the basics of programing and i done some work in PHP .
    i only want to know how to save the game on the PC and load it please :)
    thank you and excuse me .
     
  15. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi there,
    If you send me an email at moodkie.com/contact, I'll try my best to assist you personally so we don't have a huge trail of posts on this forum :)
    All the best,
    Joel
     
    Last edited: Jun 1, 2017
  16. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    The latest update is now available with SaveRaw(byte[]), SaveRaw(TextAsset), a new menu item which allows you to change the default settings, and there's a PlayMaker™ action available from the Downloads section on the Easy Save homepage.

    All the best,
    Joel
     
  17. fanjules

    fanjules

    Joined:
    Nov 9, 2011
    Posts:
    167
    I notice with easysave 1 (not tried in easysave 2 yet) that if I save an array of ushort[] and load it in another program, it doesn't quite work as EasySave includes a header. This seems unnecessary as surely it should operate in exactly the same way as loading/saving byte arrays (which are saved with no header).

    This is a problem when transferring or receiving data to servers, which then have to recreate the header (again, not convinced the header really needs to be there).
     
  18. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Thanks for your question.

    As the post above says, we've just included a SaveRaw method and hope to include more SaveRaw methods in the near future. Before then, we're hoping to include XML methods as most people will find this easier to parse than raw data.

    We include header data in our non-raw files because it allows us to parse the data more efficiently, making it much faster, and it also allows us to throw errors if necessary. It's also used in ES2 for a number of other things, including tags.

    Regards,
    Joel
     
  19. fanjules

    fanjules

    Joined:
    Nov 9, 2011
    Posts:
    167
    Any time line for implementing the random access read/write? (working with a simple byte array will suffice)
     
  20. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    The latest version of ES2 has a low memory mode (which you can activate by changing the default settings) which loads data directly from file instead of preloading it into memory (which addresses the memory part of your post from a while back).

    We've got more raw functions on our To Do list, including ones which will let you access the raw bytes of a file by specifying the position in the stream (which will be what you want), but I can't currently give an estimate on how long it's going to take. Because it's coming towards the end of the tax year, bureaucracy is taking up a lot of time which we would love to spend on ES2; it makes it difficult to timeline anything :( I've put it fairly high on our priority list as we can see it being useful to a lot of people, but I'll keep you updated on progress regardless.
     
  21. mrbdrm

    mrbdrm

    Joined:
    Mar 22, 2009
    Posts:
    510
    just wanted to say THANK YOU for the playmaker action . i love you :)
     
  22. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Not a problem :) If there are any other features you would like to see, let us know!
     
  23. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    493
    Hi Joel
    As a novice EasySave 1 user I'm wondering if ES2 would be ready now for me to use? Or should I not use it at all?

    Also, with the filename that I create to save to, for example "mySaveData.txt", where do i find this file on my mac?
    I have results being saved to that file that i want to be able to clear/delete for testing purposes, but can't find any reference to it inside my mac, and figure the file must be living 'somewhere' for me to access?

    Thanks!
     
  24. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi mangoblue,

    It's safe to use ES2 :) We're waiting a short while before releasing it officially as at the moment we are tied up with our end of tax year tasks.

    By default, ES2 saves to PlayerPrefs (though we might change this). If you go to the new Easy Save drop down menu, you can add a Default Settings object which lets you change the default settings, include the Save Location.

    When saving to file, by default it saves to Application.persistentDataPath, so just do:
    Code (csharp):
    1. Debug.Log(Application.persistentDataPath);
    to find the exact save location. On Mac this is along the lines of:
    Code (csharp):
    1. /Users/yourUserName/Library/Caches/YourCompanyName/YourUnityProjectName/
    All the best,
    Joel
     
  25. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    493
    Arch! Found it in my cache! Why is it e v e r y t i m e I post on unity, even if it's after a week of problem searching, the answer ALWAYS arrives AFTER I've just posted!! Anyway, sorry for taking up space here :p
     
  26. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Not a problem! I get asked this question a lot, so it's worth me posting the answer here anyway :)
     
  27. CoCoNutti

    CoCoNutti

    Joined:
    Nov 30, 2009
    Posts:
    493

    Whoops just saw this, that was quick! Thanks :) So if ES2 saves to PlayerPrefs, rather than a .txt (or any other extension) file now? Is it still possible to encrypt this? Thanks!
     
  28. Izitmee

    Izitmee

    Joined:
    Jan 27, 2011
    Posts:
    3,228
    Hey Joel,

    I'm using EasySave2 to save to PlayerPrefs (and am totally happy with it), but I was wondering: is there some chance that something happens (electricity shuts down, or in case of Android phones the phone locks, etc.) and saved data becomes corrupt? This is obviously a possibility when saving to file, but I was wondering if PlayerPrefs was instead 100% safe. And if not, do you have any advice about how to check if saved data is corrupt, and eventually restore a backup?

    Thanks :)
     
  29. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    ES2 can save to both PlayerPrefs and File, and encryption works for both. If you take a look at the Parameters, things will hopefully become a bit clearer!

    If you get a chance, also take a look at the Identifiers page. An Identifier is basically your file path, but it can take many forms in ES2.
     
  30. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi again,

    Great Question. When ES2 finds corrupt data, it throws an ES2FormatException. It's very, very unlikely that data will become corrupt as ES2 saves data so quickly. However, it's always worth taking this into consideration just in case. I should also note that PlayerPrefs would be no more or less reliable in this situation as it too has to save to file at some point.

    For the time being, the best way to create backups would be to save the data twice, and give the backup save a *.backup extension (or anything to identify it as the backup). Then you could do something like this when loading:

    Code (csharp):
    1.  
    2. try
    3. {
    4.     return ES2.Load<MyType>("myFile.txt");
    5. }
    6. catch (ES2FormatException e)
    7. {
    8.     if(ES2.Exists("myFile.backup"))
    9.         return ES2.Load<MyType>("myFile.backup");
    10. }
    11.  
    I like the backup idea a lot, so I've added backup methods to our increasingly large To Do list. This would consist of an automatic backup option which would automatically create backups and load them when data becomes corrupt, and some methods for manual backups.

    I'm afraid progress is going to be a little slow for the next couple of weeks as this is our busiest time of the year, but I personally cannot wait to continue with our To Do list and get ES2 officially released :)
     
  31. Izitmee

    Izitmee

    Joined:
    Jan 27, 2011
    Posts:
    3,228
    Thanks a lot for the in-depth answer Joel :) Wonderful plugin and awesome support :)
     
  32. U2

    U2

    Joined:
    Aug 12, 2008
    Posts:
    215
    Hey there.. Pretty excited about this tool but have one question..

    I am trying to save an array of particles from a galaxy generator I have created. The function basically models a galaxy of stars and assigns the Vector3 (x,y,z coords) of each star to each particles.position in my loop. I also assign color and size etc..

    My particles array is made from

    var particles = new ParticleSystem.Particle[numberStars];

    My save code is like this..

    ES2.Save(particles, "Galaxy", ezSettings);

    I get the Not Supported Exception and am wondering if there is a better way to do this or would it be possible for you to add the particles array type to Easy Save? I guess if need be I could also save an array of Vector3 types only but I'm not sure this would work either plus I'd lose some of the other attributes of the particles such as size and color etc..
     
  33. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523

    Hi rutecht,

    It's not possible to save particles at the moment, but we'll add it to our To Do list. A list of supported types can be found here.

    As you suggest, the best way of saving this would be to save each of the properties as a separate array. So you could create an array containing all of the position values, another array containing all of the Color values and another containing all of the size values, and then save these to file. I hope this helps.

    All the best,
    Joel
     
  34. RayWolf

    RayWolf

    Joined:
    Mar 24, 2012
    Posts:
    87
    Hi,

    is this asset also for people who are not programmers? e.g. artist-guys? Much to sript or to even code? Can guys like me use 'playmaker' or is the editing for saving values (player health/position/choices-he-made-flags etc) easy and structured?

    sry Im not well informed, but the time to save values here will come too :p!

    regards,
    Ray
     
  35. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi Ray,

    There is a Playmaker action available (which can be downloaded from http://www.moodkie.com/easysave), and also a drag-and-drop script for those who do not have Playmaker. At current it just saves position, rotation, scale, Mesh, SphereCollider, BoxCollider, CapsuleCollider and MeshCollider, but we're hoping to extend the Playmaker action to support all of the Playmaker supported types in the near future.

    Best wishes,
    Joel
     
  36. Izitmee

    Izitmee

    Joined:
    Jan 27, 2011
    Posts:
    3,228
    @RayWolf: as an EasySave 2 user, I have to add that Joel was even too modest about the easiness of scripting. Even if you don't use PlayMaker or drag-and-drop scripts, there is really very little scripting to do (if we exclude the scripting you might need to collect the data you need to save, whose length depends on the way your project works).
     
  37. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Thanks lzitmee, I couldn't have said it better myself :)

    I should also note that if there's something in particular that you want to save and aren't sure of how to do it, I'm always happy to write an example script for you.
     
    Last edited: Jun 1, 2017
  38. profanicus

    profanicus

    Joined:
    Nov 23, 2009
    Posts:
    286
    Hi, I was wondering if playerprefs saving is working in the latest beta? Or if there is some trick I am missing. :)

    I did a quick test with the ES2Auto on a couple of gameobjects that I am dragging around in the editor in Play Mode; it saves fine to a file but if I switch the advanced settings to playerprefs, it doesn't save.
     
  39. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi profanicus,

    It's currently working fine at our end, so I need to know a bit more info so I can try and replicate your problem :)

    Have you made sure that each of your ES2Auto scripts is using a different Unique Tag?
    If you've changed any settings, what have you changed them to?
    Are you using a Default Settings object, and if so, what settings have you changed on it?

    It might be easier if you email me direct at moodkie.com/contact.

    All the best,
    Joel
     
    Last edited: Jun 1, 2017
  40. profanicus

    profanicus

    Joined:
    Nov 23, 2009
    Posts:
    286
    Joel, thanks for resolving the playerprefs issue, now please bear with me for a couple of other beginner queries ... :)

    First, is there no bool support in ES2? I don't see it in supported types, but I see it mentioned in the first post for ES1.

    What is the difference and when would you use/choose between the 2 optimize modes?

    I get tags, they are for allowing saving of multiple objects of the same type into the one file right? So in the example below, are we defaulting to "append" mode in the settings? Does multiple calls to the below method in "overwrite" mode result in a single saved mesh, even when using tags?

    Also, accessing the "tag" field (settings.tag) as used below is missing for me, i.e. I do not get a "tag" field.

    Code (csharp):
    1.  
    2. // A function which saves the name of the object it's attached to.
    3. public void SaveMesh(Mesh mesh, string tag)
    4. {
    5. ES2Settings settings = new ES2Settings();
    6. settings.tag = tag;
    7. settings.saveTangents = false;
    8. ES2.Save(mesh, "myMesh.mesh", settings);
    9.  
    10. }
     
    Last edited: Mar 31, 2012
  41. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Bool is definitely supported, I just forgot to add it to the Supported Types page. With regards to the tag field, that's also my mistake. The tag field will be available in Monday's Asset Store update :)

    Basically OptimizeMode.Fast uses more memory, but is about 20% quicker on average. OptimizeMode.LowMemory is slower, but uses much less memory. It's only really relevant if you're saving to file rather than PlayerPrefs.

    Actually tags can be used to save multiple objects of any supported type into a file. For example, this is perfectly fine:

    Code (csharp):
    1.  
    2. // Save a Vector3.
    3. ES2.Save( transform.position,  "myFile.txt?tag=myPosition" );
    4. // Save a string to the same file, but with a different tag.
    5. ES2.Save( gameObject.name,  "myFile.txt?tag=myName" );
    6.  
    7. // As long as you load them using the right Load type, they'll load fine.
    8. transform.position = ES2.Load<Vector3>( "myFile.txt?tag=myPosition" );
    9. gameObject.name = ES2.Load<string>( "myFile.txt?tag=myName" );
    10.  
    I'll clarify what happens when overwriting/appending. When you overwrite, it will overwrite only the data with the same tag. Using the method in your example:

    Code (csharp):
    1.  
    2. // This will overwrite
    3. SaveMesh(myMesh, "myTag");
    4. SaveMesh(myOtherMesh, "myTag");
    5.  
    6. // This will not overwrite
    7. SaveMesh(myMesh, "aTag");
    8. SaveMesh(myOtherMesh, "aDifferentTag");
    9.  
    When you append, it adds the tag to the same file multiple times. You can then load all of the data with a given tag using the LoadAll methods; it'll return an array of your type. I must note that you cannot currently use LoadAll to load arrays.

    And as another quick note to anyone who's interested, if you don't specify a tag, it'll use the default tag (which is a blank string).

    I hope this all makes sense. When I get time I really want to revamp the documentation to make it easier to understand; I'll maybe turn it into a wiki.

    All the best,
    Joel
     
  42. profanicus

    profanicus

    Joined:
    Nov 23, 2009
    Posts:
    286
    Yep, fantastic - that has cleared things up for me substantially, thanks.
     
  43. EarthLaunch

    EarthLaunch

    Joined:
    Mar 7, 2012
    Posts:
    62
    @joeltebbett This tool is awesome, thanks for it.

    Edit: Actually now I'm not sure about the below, I may have run the wrong build. Edit2: I was almost certainly wrong, sorry. Leaving this up just in case.

    I came across something you might want to know about. When using ES2.Exists(Identifier) on a ~80MB encrypted local file (containing tagged data that's about ~4MB per tag), it used an extreme amount of memory. In some situations that works, in others it throws an out of memory exception. I worked around it by skipping the ES2.Exists() and just enclosing my straight ES2.LoadArray() in a try/catch block.
     
    Last edited: Apr 2, 2012
  44. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi EarthLaunch,

    Thanks for the heads up. The Try/Catch method is fine to use; here's a list of Exceptions you can catch if you run into any errors.

    ES2.Exists searches the file for a tag, and it does this by loading the file into memory, which is why it uses quite a lot of memory.

    If you were not already aware, you can activate Low Memory mode, which loads directly from file and is perfect for large files. This can be done by creating an ES2Settings object, setting it's optimizeMode variable to ES2.OptimizeMode.LowMemory and supplying it as a third parameter when using ES2.Load. This is not fully documented yet, and does not currently work with ES2.Exists. This will make much more sense when we revamp the documentation :)

    All the best,
    Joel
     
  45. profanicus

    profanicus

    Joined:
    Nov 23, 2009
    Posts:
    286
    Oooh I've been using ES2.Exists pretty much every time I load something, which is a fair bit. Sounds like this is not good practice?

    edit: Also, I have been trying unsuccessfully to save/load a List of Transforms. Should this work?

    _keysHeld is a List<Transform>, _identifier is a string.
    Code (csharp):
    1.  
    2. ES2.Save(_keysHeld, _identifier);
    3. _keysHeld = ES2.LoadList<Transform>(_identifier);
    4.  
    I get a "ES2TypeNotSupportedException" when loading.
     
    Last edited: Apr 3, 2012
  46. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Hi profanicus,

    ES2.Exists is fine when only saving small amounts of data (by small amounts, I mean anything under 10mb).

    With regards to loading Transforms, at the moment you need to load them using the self-assigning functions, which only work with native arrays (using the ES2.LoadArray<Transform>( identifier, Transform[] transforms ). The reason for this is that to create a Transform you also have to create a GameObject, and in Easy Save 1 this confused quite a few people.

    As it seems like it would be useful for you to do this, in the next update I'll add the ability to load Transforms like you would load any other data, though I'll make it clear in the documentation that it'll add an empty GameObjects to the scene for every Transform that you load.

    All the best,
    Joel
     
  47. RayWolf

    RayWolf

    Joined:
    Mar 24, 2012
    Posts:
    87
    This sounds indeed cool. I will keep this asset in mind :)!
     
  48. EarthLaunch

    EarthLaunch

    Joined:
    Mar 7, 2012
    Posts:
    62
    Joel,

    Thanks for your informative response. I did indeed find and use the LowMemory setting, and it works well.

    To anyone reading this thread worried about memory: I found that ES2.Exists does use a little memory for my 80MB file, but not the "extreme" amount I thought in my first post. That was my own mistake elsewhere in my code. Joel's explanation matches my experience.
     
  49. profanicus

    profanicus

    Joined:
    Nov 23, 2009
    Posts:
    286
    I was wondering how people are handling the need for a unique tag when saving to a single file? I have to save the state of a lot of objects in a room so the player can reset a puzzle when required.

    I have been using a manually-entered "Unique ID" field for all my objects that need to get saved, but am finding it extremely error prone.

    InstanceID is not persistent between sessions so can't use that.

    I was thinking something based off parsing the starting transform position and creating an ID from that (assuming I don't have 2 of the same type at the same position), but I am interested in what others do for this.
     
  50. joeltebbett

    joeltebbett

    Joined:
    Oct 18, 2009
    Posts:
    523
    Quite a few people have requested that Unity include a unique Instance ID, so I've got my fingers crossed for Unity 3.6 :)

    Most people tend to give each object a unique name and use this. It's generally good form to do this anyway, even if you're just adding a number to the end of each. The cleanest way to do it would be to instantiate objects at runtime, so then having a unique tag becomes less important.

    If you find a way of doing it which works well for you, let us know!
     
unityunity