Search Unity

Question [SOLVED] Persistent data storage of transforms and their parent between runtimes

Discussion in 'Scripting' started by Sparkyso, Jan 9, 2023.

  1. Sparkyso

    Sparkyso

    Joined:
    Jan 9, 2018
    Posts:
    2
    What I need is a way to store transforms, together with their parents (i.e. place in the hierarchical scene structure) in such a way that it is persistent between multiple editor/runtime sessions.

    My usecase is that a user must be able to attach transforms to other (moving) transforms and that this information must be remain saved for the next runtime.

    I do not know a way to reduce this information to Plain Old Data. If it were just world location and orientations that wouldnt be so hard. The resources I found regarding this subject e,g, (https://blog.unity.com/technology/persistent-data-how-to-save-your-game-states-and-settings) never related to scene hierarchical data. Attempts to create a unique adres for a transform that can be found again the next runtime also failed such as:

    • chaining the transform names (e.g. car.spoiler.wing) doesnt work since transform child names need not be unique
    • Using the transform GetInstanceID, doesnt work since it is not the same the next runtime.
    Any help would be much appreciated.
     
  2. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    Something like this should be sufficient:
    Code (CSharp):
    1. public class Node {
    2.   public int id;
    3.   public int parentId;
    4.   // whatever other data you need
    5. }
    Just loop over all your objects and assign them an incremental ID before saving (or assign one as they are created).
     
    Sparkyso and Bunny83 like this.
  3. Laperen

    Laperen

    Joined:
    Feb 1, 2016
    Posts:
    1,065
    Is this hierachy of objects part of the scene, or prefabs instantiated at runtime?
     
  4. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,619
    Yeah, if I need to store persistent data between play sessions for a GO, I attach a component with an ID and use that to identify the object.

    Note that both the GO which the data belongs to and any other GOs referenced by that data need to have a persistent ID. If anything can be re-parented to anything then this means you need an ID on every GameObject.

    Also note that sequential ints will cause issues if you need to reference across scenes, or in a variety of other circumstances (e.g. version control merging). I use a random GUID, the overhead hasn't been an issue, and there's plenty of room for optimisation should it come to that.
     
    Bunny83 and spiney199 like this.
  5. PraetorBlue

    PraetorBlue

    Joined:
    Dec 13, 2012
    Posts:
    7,909
    I'll admit I may have slightly misread the original question in this thread. My post was made with the assumption this was needed just for game save files. In such a case:
    • There's no requirement of the ID being persistent from save file to save file
    • There's no requirement to have a consistent ID in the file and at runtime
    • There's no version control churn to worry about
    If you need something serialized for the editor, you will want to use something a little more sophisticated than a serial ID assignment, agreed.
     
    angrypenguin likes this.
  6. Sparkyso

    Sparkyso

    Joined:
    Jan 9, 2018
    Posts:
    2
    All, thanks for taking the effort to respond.

    The scenes I want to apply this to have large/complex models with many transforms stacked on top of eachother. I dont think it would be great for performance if I needed to add something (e.g. identifier scripts) to all of them to make it work. Which is what the current proposed solutions rely on.

    The objects are regular gameobjects already present in the scene, no prefab instance support required for my implementation.
     
  7. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,686
    This is why humans are INCREDIBLY bad at predicting computer performance.

    You could probably add ten thousand identifiers to every single item in your model and things would be plenty fine speed-wise. Why? Because they're just lying around in memory.

    You could certainly add one identifier to each item!

    And it isn't optional either. If you have an ad-hoc set of data and someone applies ad-hoc changes to it, and you wish to persist those changes restore them later, then somehow you have to get the changes back onto them.

    Think of it like a seating chart at a dinner party: the chart MUST contain the person's name AND their location.

    Otherwise when the guests arrive (eg, you load your game), they won't know where to go.

    Fortunately you are NOT the first person to study this problem, so learn from others.

    Load/Save steps:

    https://forum.unity.com/threads/save-system-questions.930366/#post-6087384

    An excellent discussion of loading/saving in Unity3D by Xarbrough:

    https://forum.unity.com/threads/save-system.1232301/#post-7872586

    Loading/Saving ScriptableObjects by a proxy identifier such as name:

    https://forum.unity.com/threads/use...lds-in-editor-and-build.1327059/#post-8394573

    When loading, you can never re-create a MonoBehaviour or ScriptableObject instance directly from JSON. The reason is they are hybrid C# and native engine objects, and when the JSON package calls
    new
    to make one, it cannot make the native engine portion of the object.

    Instead you must first create the MonoBehaviour using AddComponent<T>() on a GameObject instance, or use ScriptableObject.CreateInstance<T>() to make your SO, then use the appropriate JSON "populate object" call to fill in its public fields.

    If you want to use PlayerPrefs to save your game, it's always better to use a JSON-based wrapper such as this one I forked from a fellow named Brett M Johnson on github:

    https://gist.github.com/kurtdekker/7db0500da01c3eb2a7ac8040198ce7f6

    Do not use the binary formatter/serializer: it is insecure, it cannot be made secure, and it makes debugging very difficult, plus it actually will NOT prevent people from modifying your save data on their computers.

    https://docs.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-security-guide