Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice
  3. Join us on November 16th, 2023, between 1 pm and 9 pm CET for Ask the Experts Online on Discord and on Unity Discussions.
    Dismiss Notice

[Discontinued] Unity Save Load Utility (Free!) - Save and load your data

Discussion in 'Assets and Asset Store' started by Cherno, Oct 9, 2016.

  1. yaaru

    yaaru

    Joined:
    Mar 3, 2017
    Posts:
    15
    Hey. I try to save GameObject (primitive Sphere), but initially the components of the object did not load after saving.

    I fixed SaveLoadUtility -> UnpackComponent:
    // add components that are missing
    If (go.GetComponent (obc.componentName) == null) {
    Type componentType = Type.GetType (obc.componentName);
    Go.AddComponent (componentType);
    }


    on

    // add components that are missing
    If (go.GetComponent (obc.componentName) == null) {
    Type componentType = Type.GetType ("UnityEngine." + Obc.componentName + ", UnityEngine");
    Go.AddComponent (componentType);
    }

    Otherwise the type was always returned null.


    Now the components of the object are loaded but the MeshFilter well has a Mesh,
    And MeshRenderer does not have any materials.

    So it should be?
     
  2. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    By default, only the Transform component and those components that inherit from MonoBehavior ("scripts") are saved and loaded. If other Types should be handled, you have to find your own workarounds for those, for example by writing an ISerializationSurrogate. Check the Manual and Quick Start Guide for more information.
     
  3. Nargarnd

    Nargarnd

    Joined:
    Jul 25, 2017
    Posts:
    4
    Hey Cherno, I found USLU some days ago and I think it's just what I needed but I'm having a hard time trying to create my own surrogate.

    I'm trying to serialize a Mesh, cause in runtime I'm modifying the meshes of some GameObjects and I want to be able to save and load and keep the state of the objects in scene.

    So what I do in runtime is:
    1. I modify the gameObject the way I want.
    2. Before saving the scene I add a objectIdentifier to the gameObject
    3. I create a prefab of the object
    4. Refresh the prefab Dictionary so SaveLoadUtility can find my new prefab (See RefreshDictionary method)
    5. Save the scene (The mesh should be serialized)
    6. Load the scene (The mesh should be deserialized)

    RefreshDictionary method:
    Code (CSharp):
    1.     public void RefreshDictionary()
    2.     {
    3.         prefabDictionary = new Dictionary<string, GameObject>();
    4.         ObjectIdentifier[] prefabs_oi = Resources.LoadAll<ObjectIdentifier>("");
    5.         foreach (ObjectIdentifier oi in prefabs_oi)
    6.         {
    7.             prefabDictionary.Add(oi.gameObject.name, oi.gameObject);
    8.             if (debugController.loadPrefab)
    9.             {
    10.                 Debug.Log("Added GameObject to prefabDictionary: " + oi.gameObject.name);
    11.             }
    12.         }
    13.     }
    So I wrote my own surrogate for the Mesh:

    Surrogate Code:
    (I know, I could just serialize the Arrays, I read that after coding this and I'm going to change it but this should also work)
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Runtime.Serialization;
    3. using UnityEngine;
    4.  
    5. public class MeshSurrogate : ISerializationSurrogate
    6. {
    7.  
    8.     // Method called to serialize a Vector3 object
    9.     public void GetObjectData(System.Object obj, SerializationInfo info, StreamingContext context)
    10.     {
    11.         UnityEngine.Mesh m = (UnityEngine.Mesh)obj;
    12.         Vector3[] vertices = m.vertices;
    13.         int[] triangles = m.triangles;
    14.  
    15.         info.AddValue("nombre", m.name);
    16.         info.AddValue("numVertices", vertices.Length);
    17.    
    18.         for (int idVertice = 0; idVertice < vertices.Length; idVertice++)
    19.         {
    20.             info.AddValue("vertice" + idVertice, vertices[idVertice]);
    21.         }
    22.  
    23.         info.AddValue("numTriangulos", triangles.Length);
    24.         for (int idTriangle = 0; idTriangle < triangles.Length; idTriangle++)
    25.         {
    26.             info.AddValue("triangulo" + idTriangle, triangles[idTriangle]);
    27.         }
    28.     }
    29.  
    30.     // Method called to deserialize a Vector3 object
    31.     public System.Object SetObjectData(System.Object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
    32.     {
    33.         UnityEngine.Mesh m = new UnityEngine.Mesh();
    34.         m.name = (string) info.GetValue("nombre", typeof(string));
    35.  
    36.         List<Vector3> vertices = new List<Vector3>();
    37.         int numVertices = (int) info.GetValue("numVertices", typeof(int));
    38.         for (int i = 0; i < numVertices; i++)
    39.         {
    40.             vertices.Add((Vector3) info.GetValue("vertice" + i, typeof(Vector3)));
    41.         }
    42.         m.vertices = vertices.ToArray();
    43.  
    44.  
    45.         List<int> triangulos = new List<int>();
    46.         int numTriangulos = (int) info.GetValue("numTriangulos", typeof(int));
    47.         for (int i = 0; i < numTriangulos; i++)
    48.         {
    49.             triangulos.Add((int) info.GetValue("triangulo" + i, typeof(int)));
    50.         }
    51.         m.triangles = triangulos.ToArray();
    52.  
    53.         m.RecalculateNormals();
    54.  
    55.         obj = m;
    56.         return obj;
    57.     }
    58. }
    SaveLoadUtility Code:
    Code (CSharp):
    1.     private Dictionary<RefReconnecter,string> refDict;//used to reconnect fields of Type GameObject and those inheriting from Component to their respective reference instances again after loading.
    2.     [HideInInspector] private List<string> surrogateTypes = new List<string>() {
    3.         "Vector2",
    4.         "Vector3",
    5.         "Vector4",
    6.         "Quaternion",
    7.         "Color",
    8.         "Color32",
    9.         "Mesh"
    10.     };
    SaveLoadCode:
    Code (CSharp):
    1. public static void AddSurrogates(ref SurrogateSelector ss) {
    2.         MeshSurrogate Mesh_SS = new MeshSurrogate();
    3.         ss.AddSurrogate(typeof(Mesh),
    4.             new StreamingContext(StreamingContextStates.All),
    5.             Mesh_SS);
    6. }
    But the Mesh is not serialized and my code is never executed, when I load there is a gameObject, without any Mesh on it, so... i guess I am doing something wrong but I just can't figure what it is.

    I've also tried to serialize the Mesh and the MeshFilter that contains it, so I wrote another surrogate:
    MeshFilter Surrogate:
    Code (CSharp):
    1. using System.Collections.Generic;
    2. using System.Runtime.Serialization;
    3. using UnityEngine;
    4.  
    5. public class MeshFilterSurrogate : ISerializationSurrogate
    6. {
    7.  
    8.     // Method called to serialize a Vector4 object
    9.     public void GetObjectData(System.Object obj,
    10.         SerializationInfo info, StreamingContext context)
    11.     {
    12.         MeshFilter mf = (MeshFilter)obj;
    13.         Mesh m = mf.mesh;
    14.         info.AddValue("mesh", m);
    15.     }
    16.  
    17.     // Method called to deserialize a Vector4 object
    18.     public System.Object SetObjectData(System.Object obj,
    19.         SerializationInfo info, StreamingContext context,
    20.         ISurrogateSelector selector)
    21.     {
    22.         MeshFilter mf = new MeshFilter();
    23.         mf.mesh = (Mesh) info.GetValue("mesh", typeof(Mesh));
    24.  
    25.         obj = mf;
    26.         return obj;
    27.     }
    28. }
    And added this to the AddSurrogate and the dictionary but the result It's just the same, not working.

    Could you help me find out what I do wrong?
     
  4. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    First step would be to see if the ISS is actually used. You can do this by inserting Debug.Log lines. Also, keep in mind that as I wrote above, components that are not Transforms and don't inherit from MonoBehavior are not serialized by default. I suggest writing a simple MB script which only contains one (non-null) Mesh variable, and see if it is saved & loaded.
     
  5. Nargarnd

    Nargarnd

    Joined:
    Jul 25, 2017
    Posts:
    4
    Thanks Cherno, I tried that in your testing scene, I added Mesh field to the test script and set it to a capsule mesh. Then I put some debugs in my surrogate so I can see if it works... ¡And it worked!
    But, when I tried the same thing in my scene it doesn't, the debugs didn't appear on the console so the surrogate is not executing.
    I thought it could be because the componentSaveMode in the object identifier so I tried with All and Inclusive List adding my types to the componentTypesToSave List but I didn't solve anything.

    I don't know what else could it be, any ideas?
     
  6. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Nothing concrete, but in the end most problems can be solved by following the code as it is run. So, try to insert Debug.Log lines along the code path and see how much is reached.
     
  7. Nargarnd

    Nargarnd

    Joined:
    Jul 25, 2017
    Posts:
    4
    Hello again Cherno, I've trying some things in my project and I just realised that creating prefabs on runtime as I was doing was not a great idea.
    So I'm gonna try to make some changes in your scripts to try to make then work without prefabs as you said in a previous comment.
    So i've been looking into the code, and I think, if I remove the part when you instantiate a prefab and I create a empty gameObject instead, and then I write surrogates for all the types of components I'll be using it will work just fine.

    Do you think that will be enough or i'm forgeting something?
     
  8. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Off the top of my head, yes, that could work.
     
  9. ql28

    ql28

    Joined:
    Nov 17, 2012
    Posts:
    3
    Hi,
    I just found your awesome tool. But I have a problem when I try to save a gameobjet with a parent wich have a scale different to 1. The loading makes a weird result and affect the child scaling.. any solution ? :)
     
  10. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Yes, this might be possible and I have not forseen this case. I guess the solution is to apply any scaling only after the children are reconnected to the parent when loading.
     
  11. ql28

    ql28

    Joined:
    Nov 17, 2012
    Posts:
    3
    I'm trying this, thanks !
     
  12. Ironmax

    Ironmax

    Joined:
    May 12, 2015
    Posts:
    890
    Good effort but not everything can be serialized.
     
  13. Neoletum

    Neoletum

    Joined:
    Aug 19, 2017
    Posts:
    6
    Mhmm, what do you mean by saying not everything can be serialized? The childs can't be serialized?
     
  14. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    id and idParent is not supposed to be assigned by the user. It is given a random value when saving.

    If the object is a prefab, and it's hierarchy doesn't change during runtime, then there should be no problem since the prefab will simply be instantiated when loading with all it's children. If a gameobject is made a child of a child of another gameobject during runtime, then I don't think USLU supports that, you'd have to simplement this functionality yourself.
     
  15. LoryColo

    LoryColo

    Joined:
    Jun 21, 2017
    Posts:
    2
    HI, i download USLU and am having some trouble using it, it works fine as long as i try to save my map and my player but when i add objects like an NPC or my main camera the next time i try to load the map it only loads one object(for example the camera) i don't understank why since all components seem to be setup just right, clearly i need to separately save those objects that change their position so i can't just attach them to the whole static map and load them each time
     
  16. lukas2005

    lukas2005

    Joined:
    Sep 9, 2017
    Posts:
    2
    Hey i get TargetException error when trying to save something using Save Load Menu script
     
  17. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Disable all scripts of the gameobject in question and enable them one by one. Do the same for single memebers if you must.
     
  18. IAmJade

    IAmJade

    Joined:
    Aug 2, 2017
    Posts:
    1
    Cherno , Is there any problem while loading all the prefabs? Its "On Click" does not exist anymore? 'Cause as I load my environment, that specific button does not carry the "On Click".

    Do you have some thoughts regards here. Thanks.

    ps. really appreciated this package.
     
  19. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    If you are talking about saving and loading delegates: That's something I have never even considered.
     
  20. ConfirmedExpert

    ConfirmedExpert

    Joined:
    Apr 1, 2015
    Posts:
    1
    Hi Cherno,
    I got a problem with SaveAndLoad Utility that I can't build it on Windows Universal due to missing name space or cannot find in all of your scripts, do you have any suggestions? :)

    Thanks,
    Chris S
     
  21. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    I had to google what Windows Universal is so unfortunately I am of no help there.
     
    GregMeach likes this.
  22. screenname_taken

    screenname_taken

    Joined:
    Apr 8, 2013
    Posts:
    663
    @Cherno If i just put the SaveLoadUtility to the parent object of a tree of objects, I'm guessing that its children are saved as well?
    Also, if I'm already using a DoNotDestroy script of my own on the objects that need to be preserved between scenes, do i still need to use the PersistentMarker?
     
  23. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    The SaveLoadUtility would just be a script that runs the whole thing, it is supposed to be attached to a manager object of sorts that stays in the scene.
    If an ObjectIdentifier script is added to a GameObject then the data of all children is savevd as well, but this does only make sense when the prefab of the object has the same hierarchy with all children. If not, then any children not part of the prefab need their own OI component and their parents needs one as well, and also the rule that each OI object needs a prefab still applies.

    USLU does not recognize your DoNotDestroy script so you have to change USLU's code to do this if you want to keep using your own script for that purpose.
     
    screenname_taken likes this.
  24. K3babK3bab

    K3babK3bab

    Joined:
    Sep 12, 2017
    Posts:
    2
    Hey, I've used your tool to save my procedurally generated dungeons and other whole scenes in general. Got it working flawlessly after some tweaks, but only in the editor. After I build the project and try to load a previously visited scene sometimes some of the loaded objects aren't loading at all, sometimes some components are missing.

    I've spent hours trying to figure it out with no success. Any ideas why it would work flawlessly in the editor but not in the built project? I've tried numerous platforms like android, Windows, osX and the issue is the same across all of them.

    Thanks!
     
  25. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Maybe the output.log file shows some errors?
     
  26. K3babK3bab

    K3babK3bab

    Joined:
    Sep 12, 2017
    Posts:
    2
    NullReferenceException: Object reference not set to an instance of an object
    at SaveLoadUtility.SetValues (System.Object& baseInstance, System.Collections.Generic.Dictionary`2 baseDict) [0x00003] in /Users/K3babK3bab/Documents/Unity/Networking and Multiplayer Games/Assets/Unity Save Load Utility/SaveLoadUtility.cs:1046

    The above happens when your script is trying to unpack the components.
     
  27. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    I don't know why that error would occur in a build and not when run from the editor.
     
  28. jktarban

    jktarban

    Joined:
    Feb 12, 2014
    Posts:
    3
  29. Overnaut

    Overnaut

    Joined:
    Aug 25, 2017
    Posts:
    19
    At least you should cite your main source, which is obviously
    https://unity3d.com/learn/tutorials/topics/scripting/persistence-saving-and-loading-data
    with some changes.

    /Edit:
    Just for completness, I get:

    Code (CSharp):
    1. Assets/Unity Save Load Utility/SaveLoad.cs(160,18): warning CS0219: The variable `dir' is assigned but its value is never used
    2.  
    3. Assets/Unity Save Load Utility/SaveLoadUtility.cs(1091,14): warning CS0219: The variable `propertyValue' is assigned but its value is never used
    4.  
    5. Assets/Unity Save Load Utility/SaveLoadUtility.cs(1153,8): warning CS0219: The variable `baseInstanceType' is assigned but its value is never used
    6.  
    and a question @Cherno, why isn't this project on bitbucket or github?
     
    Last edited: Dec 19, 2017
  30. khos

    khos

    Joined:
    May 10, 2016
    Posts:
    1,463
    Hi, I am testing your lovely tool, works well on objects, but I have a softbody type prefab, on collision the mesh will change... when I save / load those the prefab is loaded meaning the mesh deformations are not used/loaded. is there a way around this?
     
  31. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    You'd have to find a workaround for such caases where USLU doesn't automatically save complex systems like cloth. Try to find out if it's possible to get the deform data and apply it to the softbody.
     
    khos likes this.
  32. khos

    khos

    Joined:
    May 10, 2016
    Posts:
    1,463
    I might look at saving the mesh and loading it.
     
  33. Overnaut

    Overnaut

    Joined:
    Aug 25, 2017
    Posts:
    19
    @Cherno, no answer is also an answer, understood :D
     
  34. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    It would require time and effort to learn about the ins and outs of such platforms, none of which I have been willing to spare as of yet.
     
  35. gimic9912

    gimic9912

    Joined:
    Jan 18, 2015
    Posts:
    3
    Hello, great plugin! However, I'm having a bit of a problem with saving an object with children(creating a level editor). Been messing around with it for a few hours and still can't seem to figure it out :/
    Here's what I have so far:

    How the level editor looks in the scene:
    https://ibb.co/hGU4xG

    The error I'm getting when I try to load it in:
    https://ibb.co/hVgjxG

    When Saved:
    https://ibb.co/g57eWb

    I'm adding blank ObjectIdentifiers to all children before saving:
    https://ibb.co/hQ8a4w

    Any help would be greatly appreciated :D
     
  36. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    If the parent object's prefab has these children then only the parent object needs an OI. If not and the children are dynamically added during runtime, then both the parent and the children need OIs (and prefabs).
     
  37. gimic9912

    gimic9912

    Joined:
    Jan 18, 2015
    Posts:
    3
    Thanks for the fast reply :)

    Is there a way to connect their prefab to a resource path instead of the default (Resources/Prefabs) folder. Not seeming to work on a path like (Resources/Prefabs/LevelEditObjects).
     
  38. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    Sure, just change the path... It's in SaveLoadUtility.cs IIRC.
     
  39. gimic9912

    gimic9912

    Joined:
    Jan 18, 2015
    Posts:
    3
    Awesome! thanks for the help :)
     
  40. mtang8264

    mtang8264

    Joined:
    Jan 28, 2018
    Posts:
    4
    Hey there, I'm starting to use your scripts and it seems super helpful, except I'm getting an error. It appears as though I'm never saving the GameObject to the prefabDictionary. Any idea what the issue might be?
     
  41. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    If you're getting an error that likely means that something has gone wrong somewhere ;)

    If a Prefab is in the Resources folder and has the Objectdentifier component then it should be added to the PrefabDictionary. Try the Debug settings to find out what happens exactly.
     
  42. mtang8264

    mtang8264

    Joined:
    Jan 28, 2018
    Posts:
    4
    Thanks! I didn't know that the prefabs had to be in the Resources folder. Every thing works great now!
     
  43. mtang8264

    mtang8264

    Joined:
    Jan 28, 2018
    Posts:
    4
    One more quick question. I'm wondering if there is a way to figure out how much time has passed since the save was made?
     
  44. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    A couple of
    A couple of solutions off the top of my head:
    1. If you already have some kind of in-game timer in place, you add a variable that holds the current time to the save data class. Compare it with the current time again when loaded.
    2. Similar to the way above, use the system time. MicroSoft Developer Network has information on accessing system time.
     
  45. acedevelope

    acedevelope

    Joined:
    Mar 24, 2017
    Posts:
    6
    Hey man nice tool i get a little error....
     
  46. Deleted User

    Deleted User

    Guest

    What do I do with the script simply named "SaveLoad.cs"? Do I just leave it? I followed the quick start instructions, and yet my system doesn't work. I basically have a block building game where blocks are instantiated to form random terrain. I added the ObjectIdentifier script to the prefabs that get instantiated and didn't change anything but the "Prefab Name" variable. Everything seems to run correctly, and yet the level doesn't save when I click the save button, then the load button in the basic GUI? It just removes everything not marked with the PersistanceMarker. So far, after weeks of searching, this is the only save system that seems to work for my situation. I'm new to Serialization, so any help would be greatly appreciated. I'm hoping that this still works in modern versions of Unity.

    MacOS High Sierra, Unity 2017.3.1F1
     
  47. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    If you follow the QuickStart instructions, it wil work. Take a look at the sample scene provided to check the setup. SaveLoad.cs is a static class so you don't do anything with it.
     
  48. Deleted User

    Deleted User

    Guest

    I redownloaded the package, then opened up the test scene and tried it out. Even though the example is set up exactly like mine (Except without the test script) everything worked. In my scene, I changed the path to my desktop (Users/cvieira/Desktop) just like I did in the test, and upon saving, a file appears, but when I try to load it, everything in my scene disappears, except for the gameObjects marked with the PersistanceMarker script. I also tried with the default path, and still, nothing happens (Probably because the path doesn't exist).

    Note: When I try to load my level, I get a message that the script couldn't find a key for each prefab. This happens even when I put my prefab in the test scene. Is there something I need to set?

    Thanks for all of you help so far; Your asset is the most helpful of all that I've tried.

    The code on each of my block prefabs (with the "Grass" part, set to whatever the block is named):
    Screen Shot 2018-03-13 at 4.25.48 PM.png

    The code on my "SaveLoadManager object": Screen Shot 2018-03-13 at 4.27.55 PM.png
     
    Last edited by a moderator: Mar 13, 2018
  49. Cherno

    Cherno

    Joined:
    Apr 7, 2013
    Posts:
    515
    1. The path is missing the haard drive letter ("c:" etc.)
    2. A prefab needs the OI component which in turn has to have it's prefabName variable set to the Prefab's gameObject name. This prefab needs to be in you Resources folder, which I assume is the case. USLU will find all OI components in the Resources folder and add their respective gameObjects to the prefabs dictionarys with the prefab Name as key and the gameObject as value.
     
    Deleted User likes this.
  50. Deleted User

    Deleted User

    Guest

    Yes!!!! It saved and loaded properly! Now all I have is a simple problem with my terrain generation. Basically, each block in my terrain waits until it's possible to generate the next block, then it does so, and sets the boolean in itself named "GeneratedTerrainXAxis" or "GeneratedTerrainZAxis" to true depending on the direction it did so. I have the ComponentSaveMode set to "All", and yet this variable's state isn't saved. Should I do a system like the one shown in the example scene?

    Thanks for all your help.