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

Generate unique ID on object creation?

Discussion in 'Scripting' started by mweldon, Jan 27, 2013.

  1. mweldon

    mweldon

    Joined:
    Apr 19, 2010
    Posts:
    109
    I would like to generate a unique GUID when an object is placed into the scene that never changes. This is for purposes of saving and reloading my game. I need to be able to associate each object with some kind of unique value and I would prefer a generic solution than to use the object name or its name+position.

    I tried this C# editor script:

    Code (csharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. [CustomEditor( typeof( Guid ) )]
    6.  
    7. class GuidInspector : Editor
    8. {
    9.     public override void OnInspectorGUI()
    10.     {
    11.         Guid guid = (Guid)target;
    12.         if ( guid.guid == System.Guid.Empty )
    13.         {
    14.             guid.guid = System.Guid.NewGuid();
    15.             GUI.changed = true;
    16.         }
    17.  
    18.         EditorGUILayout.SelectableLabel( guid.guid.ToString() );
    19.  
    20.         if ( GUI.changed )
    21.         {
    22.             EditorUtility.SetDirty( target );
    23.         }
    24.     }
    25. }
    26.  
    And this is the GUID script that I would attach to my object prefabs:

    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Guid : MonoBehaviour
    5. {
    6.     [HideInInspector]
    7.     public System.Guid guid;
    8. }
    9.  
    It seems to work and the GUID persists through save and reload, but as soon as I launch the player, it generates a new GUID. I tried putting code into an OnEnable function and that didn't work. I searched around for some kind of event that runs when an object is created in the editor and I can't find anything. Is there a way to do this?
     
  2. Tordur

    Tordur

    Joined:
    Jul 28, 2012
    Posts:
    17
    Just create a function in every object that gets called which assigns the GUID, and sets a variable to false, so the GUID persists.. Or maybe I'm totally wrong..
     
  3. shaderbytes

    shaderbytes

    Joined:
    Nov 11, 2010
    Posts:
    900
  4. mweldon

    mweldon

    Joined:
    Apr 19, 2010
    Posts:
    109
    I wish it was that easy, but GetInstanceID returns a different value every time you load the scene. I need something that is generated when the object is placed into the scene via the editor and never changes. That means the same value every time I load the scene, every time I run the game, quit, reload, reboot, whatever.

    Right now the only thing I can think of to do is combine the object's name, scene name, and XYZ position into a string. Which is fine as long as objects never move or share the same location with another object, but that is pretty limiting.
     
  5. mweldon

    mweldon

    Joined:
    Apr 19, 2010
    Posts:
    109
    I made another editor script that generates GUIDs for every object in my scene. I just have to remember to run it any time I place new objects. Which is annoying, but at least I can make progress.

    Code (csharp):
    1.  
    2. public class GenerateGuids : ScriptableWizard
    3. {
    4.     [MenuItem( "Custom/Generate Guids" )]
    5.     static void Generate()
    6.     {
    7.         var objList = GameObject.FindObjectsOfType( typeof( GameObject ) );
    8.         foreach ( var obj in objList )
    9.         {
    10.             Guid guidObj = ( (GameObject)obj ).GetComponent<Guid>();
    11.             if ( guidObj != null )
    12.             {
    13.                 if ( guidObj.guid == System.Guid.Empty )
    14.                 {
    15.                     guidObj.Generate();
    16.  
    17.                     GUI.changed = true;
    18.                     EditorUtility.SetDirty( guidObj );
    19.                 }
    20.             }
    21.         }
    22.     }
    23. }
    24.  
    It sure would be nice if there were a way to get this to run automatically whenever I place a new object in the scene.
     
    Last edited: Jan 28, 2013
  6. BPPHarv

    BPPHarv

    Joined:
    Jun 9, 2012
    Posts:
    318
    If you really want to blow some cycles while in the editor perhaps EditorApplication.hierarchyWindowChanged to regenerate your list quickly.
     
  7. snlehton

    snlehton

    Joined:
    Jun 11, 2010
    Posts:
    99
    Why are you using GUI.changed? GUI.changed returns true if contents of the previous GUI element changed, and I'm quite sure your GUI.changed would return false every time as labels don't change value (they're not editable). Have you actually witnessed SetDirty being called (Log.Debug) Why not set the object dirty right after you create a new GUI?

    Also, you should do the guid setting in OnEnable, not in OnInspectorGUI. It might happen that the OnInspectorGUI doesn't get called (it's not visible etc). And you should try NOT to have side-effects in your GUI rendering anyway.

    Code (csharp):
    1.  
    2. using UnityEditor;
    3. using UnityEngine;
    4.  
    5. [CustomEditor( typeof( Guid ) )]
    6.  
    7. class GuidInspector : Editor
    8. {
    9.     public void OnEnable()
    10.     {
    11.         Guid guid = (Guid)target;
    12.         if ( guid.guid == System.Guid.Empty )
    13.         {
    14.             guid.guid = System.Guid.NewGuid();
    15.             EditorUtility.SetDirty( target );
    16.         }
    17.     }
    18.  
    19.     public override void OnInspectorGUI()
    20.     {
    21.         Guid guid = (Guid)target;
    22.        
    23.         EditorGUILayout.SelectableLabel( guid.guid.ToString() );
    24.     }
    25. }
    26.  
    Also, are you sure that the System.Guid serializes properly? Have you actually managed to get the save/load thing to work?
     
  8. mweldon

    mweldon

    Joined:
    Apr 19, 2010
    Posts:
    109
    I set GUI.changed to true on line 14, then check for it on line 19 before setting the object dirty. If you don't set GUI.changed to true when you change something, then you have to click off the object and click back to get its properties panel to update.

    This code was a template from another inspector that I wrote that had several fields that could change. For this case, yes, I could have made it simpler. Also, I tried OnEnable at one point and it had the same issue so the problem didn't appear to be with the inspector.

    I figured that out eventually. :) I had to change it to store the guid as a string to get it to save. Maybe that's the problem. I never went back and retested my original inspector after changing the guid to a string so maybe that was it.

    If you know of a way to get a real guid to serialize, please let me know! Is there a way to serialize a custom type?
     
  9. mweldon

    mweldon

    Joined:
    Apr 19, 2010
    Posts:
    109
    Yeah it looks like the problem was me trying to serialize a System.Guid. It appears to be working now. I changed it to serialize the guid as a string and convert it back the first time someone accesses it. Thanks for your help. Here are the final scripts.

    Guid.cs
    Code (csharp):
    1.  
    2. using UnityEngine;
    3.  
    4. public class Guid : MonoBehaviour
    5. {
    6.     [SerializeField]
    7.     private string guidAsString;
    8.  
    9.     private System.Guid _guid;
    10.     public System.Guid guid
    11.     {
    12.         get
    13.         {
    14.             if ( _guid == System.Guid.Empty
    15.                  !System.String.IsNullOrEmpty( guidAsString ) )
    16.             {
    17.                 _guid = new System.Guid( guidAsString );
    18.             }
    19.             return _guid;
    20.         }
    21.     }
    22.  
    23.     public void Generate()
    24.     {
    25.         _guid = System.Guid.NewGuid();
    26.         guidAsString = guid.ToString();
    27.     }
    28. }
    29.  
    GuidInspector.cs
    Code (csharp):
    1.  
    2. using UnityEditor;
    3.  
    4. [CustomEditor( typeof( Guid ) )]
    5.  
    6. class GuidInspector : Editor
    7. {
    8.     void OnEnable()
    9.     {
    10.         Guid guid = (Guid)target;
    11.  
    12.         if ( guid.guid == System.Guid.Empty )
    13.         {
    14.             guid.Generate();
    15.             EditorUtility.SetDirty( target );
    16.         }
    17.     }
    18.  
    19.     public override void OnInspectorGUI()
    20.     {
    21.         Guid guid = (Guid)target;
    22.  
    23.         EditorGUILayout.SelectableLabel( guid.guid.ToString() );
    24.     }
    25. }
    26.  
     
    Pawl likes this.
  10. sysmaya

    sysmaya

    Joined:
    Nov 30, 2013
    Posts:
    16
    Code (CSharp):
    1. string uniqueID(){
    2.         DateTime epochStart = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
    3.         int currentEpochTime = (int)(DateTime.UtcNow - epochStart).TotalSeconds;
    4.         int z1 = UnityEngine.Random.Range (0, 1000000);
    5.         int z2 = UnityEngine.Random.Range (0, 1000000);
    6.         string uid = currentEpochTime + ":" + z1 + ":" + z2;
    7.         return uid;
    8.     }
     
    Rachan likes this.
  11. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    No need for any of that, use Guid.NewGuid().ToString()
     
    SamFernGamer4k and alfpooh like this.
  12. Ziplock9000

    Ziplock9000

    Joined:
    Jan 26, 2016
    Posts:
    360
    1) Just keep the GUID in a string form instead of coinverting is back and forth unless there's a specific need for it. Strings in hash tables are fast.
    2) Test and generate GUID's in the OnValidate event.
     
    SamFernGamer4k, Snowdrama and twobob like this.
  13. Ash-Blue

    Ash-Blue

    Joined:
    Aug 18, 2013
    Posts:
    102
  14. restush96

    restush96

    Joined:
    May 28, 2019
    Posts:
    120
    @Ash-Blue Thank you. But it's a bit difficult to install. I have got an error opening Unity Editor after edited the manifest. Could you help how to write the manifest correctly? Screesshot => http://prntscr.com/15wpz4d
     
    Last edited: Jun 19, 2021