Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

ScriptableSinglton<T>

Discussion in 'Immediate Mode GUI (IMGUI)' started by BMayne, Jan 29, 2015.

  1. BMayne

    BMayne

    Joined:
    Aug 4, 2014
    Posts:
    186
    Hey,

    This question is more for the Unity team but here it goes. I am trying to use ScriptableSinglton<T> as it's a public class that has some cool functionality. My only issues is the fact that the attribute required to use it in internal. I figure if ScriptableSingleton is public why is the attribute required to use it internal?

    I also release that it is an undocumented feature but would be very useful for tool development.

    Thanks
     

    Attached Files:

  2. BMayne

    BMayne

    Joined:
    Aug 4, 2014
    Posts:
    186
    Well I solved this by pretty much just creating the class on my own. It follows Unity's design.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using DioDebug = System.Diagnostics.Debug;
    4. using UnityEditor;
    5. using UnityEditorInternal;
    6. using System.IO;
    7. using Type = System.Type;
    8. using System.Text;
    9.  
    10. public class FilePathAttribute : System.Attribute
    11. {
    12.   public enum Location
    13.   {
    14.     PreferencesFolder,
    15.     ProjectSettingsFolder,
    16.     ProjectFolder,
    17.   }
    18.  
    19.   public FilePathAttribute( string relativePath, FilePathAttribute.Location location )
    20.   {
    21.     if(string.IsNullOrEmpty(relativePath))
    22.     {
    23.       Debug.LogError( "Invalid relative path! (its null or empty)" );
    24.       return;
    25.     }
    26.     if(relativePath[0] == '/')
    27.     {
    28.       relativePath = relativePath.Substring( 1 );
    29.     }
    30.     if(location == Location.PreferencesFolder)
    31.     {
    32.       this.filepath = InternalEditorUtility.unityPreferencesFolder + "/" + relativePath;
    33.     }
    34.     else if (location == Location.ProjectFolder)
    35.     {
    36.       this.filepath = relativePath;
    37.     }
    38.     else
    39.     {
    40.       StringBuilder builder = new StringBuilder();
    41.       builder.Append( Application.dataPath.Replace( "/Assets", "" ) );
    42.       builder.Append("/ProjectSettings/");
    43.       builder.Append(relativePath);
    44.       filepath = builder.ToString();
    45.     }
    46.   }
    47.   public string filepath;
    48. }
    49.  
    50.  
    51. public abstract class ScriptableObjectSingleton<T> : ScriptableObject where T : ScriptableObject
    52. {
    53.   private static T s_instance;
    54.  
    55.   public static T instance
    56.   {
    57.     get
    58.     {
    59.       if(ScriptableObjectSingleton<T>.s_instance == null)
    60.       {
    61.         ScriptableObjectSingleton<T>.CreateAndLoad();
    62.       }
    63.       return s_instance;
    64.     }
    65.   }
    66.  
    67.   protected ScriptableObjectSingleton()
    68.   {
    69.     if(ScriptableObjectSingleton<T>.s_instance != null)
    70.     {
    71.       Debug.LogError( "ScriptableSingleton already exists. Did you query the singleton in a constructor?" );
    72.     }
    73.     else
    74.     {
    75.       ScriptableObjectSingleton<T>.s_instance = ( this as T );
    76.       DioDebug.Assert( ScriptableObjectSingleton<T>.s_instance != null );
    77.     }
    78.   }
    79.  
    80.   private static void CreateAndLoad()
    81.   {
    82.     DioDebug.Assert( ScriptableObjectSingleton<T>.s_instance == null );
    83.     string filePath = ScriptableObjectSingleton<T>.GetFilePath();
    84.     if(!string.IsNullOrEmpty(filePath))
    85.     {
    86.       InternalEditorUtility.LoadSerializedFileAndForget( filePath );
    87.     }
    88.     if(ScriptableObjectSingleton<T>.s_instance != null)
    89.     {
    90.       T t = ScriptableObjectSingleton<T>.CreateInstance<T>();
    91.       t.hideFlags = HideFlags.HideAndDontSave;
    92.     }
    93.     DioDebug.Assert( ScriptableObjectSingleton<T>.s_instance != null );
    94.   }
    95.  
    96.   public static string GetFilePath()
    97.   {
    98.     Type typeFromHandle = typeof( T );
    99.     FilePathAttribute[] filePaths = typeFromHandle.GetCustomAttributes( typeof( FilePathAttribute ), true ) as FilePathAttribute[];
    100.  
    101.     for( int i = 0; i < filePaths.Length; i++ )
    102.     {
    103.       if(!string.IsNullOrEmpty(filePaths[i].filepath))
    104.       {
    105.         return filePaths[i].filepath;
    106.       }
    107.     }
    108.     return null;
    109.   }
    110.  
    111.  
    112.   protected virtual void Save(bool saveAsText)
    113.   {
    114.     if(ScriptableObjectSingleton<T>.s_instance == null)
    115.     {
    116.       Debug.Log( "Cannot save ScriptableSingleton: no instance!" );
    117.       return;
    118.     }
    119.     string filePath = ScriptableObjectSingleton<T>.GetFilePath();
    120.     if(!string.IsNullOrEmpty(filePath))
    121.     {
    122.       string directoryName = Path.GetDirectoryName( filePath );
    123.       if(!Directory.Exists(directoryName))
    124.       {
    125.         Directory.CreateDirectory( directoryName );
    126.       }
    127.       InternalEditorUtility.SaveToSerializedFileAndForget( new T[]
    128.         {
    129.           ScriptableObjectSingleton<T>.s_instance,
    130.         }, filePath, saveAsText );
    131.     }
    132.   }
    133. }
    134.