ParnassianStudios

LocalPrefs.cs

Jan 17th, 2018
458
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.85 KB | None | 0 0
  1. using System.Collections;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.IO;
  5. using System.Runtime.Serialization.Formatters.Binary;
  6. using UnityEngine;
  7. using ParnassianStudios.General.Collections;
  8.  
  9. namespace ParnassianStudios.General.Project
  10. {
  11.     /// <summary>
  12.     /// A singleton-like database for game preferences.
  13.     /// </summary>
  14.     [CreateAssetMenu(fileName = "LocalPrefs", menuName = "Local Prefs")]
  15.     public class LocalPrefs : ScriptableObject, ISerializationCallbackReceiver
  16.     {
  17.         /// <summary>
  18.         /// The local path to the runtime LocalPrefs, from PersistentDataStorage.
  19.         /// </summary>
  20.         public const string PATH_LOCAL = "LocalPrefs.sd";
  21.  
  22.         /// <summary>
  23.         /// The short path to the default LocalPrefs database, from Resources
  24.         /// </summary>
  25.         public const string PATH_DEFAULT = "LocalPrefs";
  26.  
  27.         /// <summary>
  28.         /// The full path to the default LocalPrefs database, from Assets
  29.         /// </summary>
  30.         public const string PATH_DEFAULT_FULL = @"Assets/Resources/LocalPrefs.asset";
  31.  
  32.  
  33.         // self-singleton reference
  34.         private static LocalPrefs _instance;
  35.         public static LocalPrefs instance
  36.         {
  37.             get
  38.             {
  39.                 if (_instance == null)
  40.                 {
  41.                     // first try loading from the local file, if we're not in the editor
  42.                     if (!Application.isEditor)
  43.                     {
  44.                         _instance = LoadPrefsFromFile(Application.persistentDataPath + PATH_LOCAL);
  45.                     }
  46.  
  47.                     // if still null, load the default database instead
  48.                     if (_instance == null)
  49.                     {
  50.                         _instance = Resources.Load<LocalPrefs>(PATH_DEFAULT);
  51.  
  52.                         if (_instance == null)
  53.                             _instance = ScriptableObject.CreateInstance<LocalPrefs>();
  54.  
  55.                         _instance._dirty = true;
  56.                     }
  57.                 }
  58.                 return _instance;
  59.             }
  60.         }
  61.  
  62.  
  63.         // contains unsaved changes
  64.         private bool _dirty = false;
  65.  
  66.  
  67.         // string-keyed collections
  68.         [SerializeField]
  69.         private List<StringStringKVP> _stringKeyedStrings;
  70.  
  71.         [SerializeField]
  72.         private List<StringIntKVP> _stringKeyedInts;
  73.  
  74.         [SerializeField]
  75.         private List<StringFloatKVP> _stringKeyedFloats;
  76.  
  77.         [SerializeField]
  78.         private List<StringBoolKVP> _stringKeyedBools;
  79.  
  80.         // string-keyed lookups
  81.         [System.NonSerialized]
  82.         private Dictionary<string, string> _stringKeyedStringsLookup;
  83.  
  84.         [System.NonSerialized]
  85.         private Dictionary<string, int> _stringKeyedIntsLookup;
  86.  
  87.         [System.NonSerialized]
  88.         private Dictionary<string, float> _stringKeyedFloatsLookup;
  89.  
  90.         [System.NonSerialized]
  91.         private Dictionary<string, bool> _stringKeyedBoolsLookup;
  92.  
  93.  
  94.         // int-keyed collections
  95.         [SerializeField]
  96.         private List<IntStringKVP> _intKeyedStrings;
  97.  
  98.         [SerializeField]
  99.         private List<IntIntKVP> _intKeyedInts;
  100.  
  101.         [SerializeField]
  102.         private List<IntFloatKVP> _intKeyedFloats;
  103.  
  104.         [SerializeField]
  105.         private List<IntBoolKVP> _intKeyedBools;
  106.  
  107.         // int-keyed lookups
  108.         [System.NonSerialized]
  109.         private Dictionary<int, string> _intKeyedStringsLookup;
  110.  
  111.         [System.NonSerialized]
  112.         private Dictionary<int, int> _intKeyedIntsLookup;
  113.  
  114.         [System.NonSerialized]
  115.         private Dictionary<int, float> _intKeyedFloatsLookup;
  116.  
  117.         [System.NonSerialized]
  118.         private Dictionary<int, bool> _intKeyedBoolsLookup;
  119.  
  120.  
  121.         // gets called whenever the object is serialized in the editor
  122.         void ISerializationCallbackReceiver.OnBeforeSerialize() { }
  123.  
  124.         // gets called whenever the object is deserialized in the editor
  125.         void ISerializationCallbackReceiver.OnAfterDeserialize()
  126.         {
  127.             InitializeAllLookups();
  128.         }
  129.  
  130.         // gets called at runtime just before the scene loads
  131.         [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
  132.         private static void RuntimeInitializeOnLoad()
  133.         {
  134.             instance.InitializeAllLookups();
  135.         }
  136.  
  137.  
  138.         /// <summary>
  139.         /// Will initialize all of the lookup tables in the class. Because these are not
  140.         /// serialized by the Unity serialization system, they need to be reconstructed
  141.         /// whenever the data arrays are changed- this is the reason for both the
  142.         /// serialization callback and runtime initialization method above.
  143.         /// </summary>
  144.         private void InitializeAllLookups()
  145.         {
  146.             InitializeLookup(ref _stringKeyedStringsLookup, _stringKeyedStrings.CastList<StringStringKVP, KVP<string, string>>());
  147.             InitializeLookup(ref _stringKeyedIntsLookup, _stringKeyedInts.CastList<StringIntKVP, KVP<string, int>>());
  148.             InitializeLookup(ref _stringKeyedFloatsLookup, _stringKeyedFloats.CastList<StringFloatKVP, KVP<string, float>>());
  149.             InitializeLookup(ref _stringKeyedBoolsLookup, _stringKeyedBools.CastList<StringBoolKVP, KVP<string, bool>>());
  150.  
  151.             InitializeLookup(ref _intKeyedStringsLookup, _intKeyedStrings.CastList<IntStringKVP, KVP<int, string>>());
  152.             InitializeLookup(ref _intKeyedIntsLookup, _intKeyedInts.CastList<IntIntKVP, KVP<int, int>>());
  153.             InitializeLookup(ref _intKeyedFloatsLookup, _intKeyedFloats.CastList<IntFloatKVP, KVP<int, float>>());
  154.             InitializeLookup(ref _intKeyedBoolsLookup, _intKeyedBools.CastList<IntBoolKVP, KVP<int, bool>>());
  155.         }
  156.  
  157.         /// <summary>
  158.         /// Initializes the String-keyed lookup table.
  159.         /// </summary>
  160.         private void InitializeLookup<T1, T2>(ref Dictionary<T1, T2> lookup, IList<KVP<T1, T2>> list)
  161.         {
  162.             if (lookup == null)
  163.                 lookup = new Dictionary<T1, T2>();
  164.             else
  165.                 lookup.Clear();
  166.  
  167.             for (int i = 0; i < list.Count; i++)
  168.                 lookup[list[i].Key] = list[i].Value;
  169.         }
  170.  
  171.  
  172.         /// <summary>
  173.         /// Returns a bool indicating that the key exists in the database.
  174.         /// </summary>
  175.         public static bool HasString(string key)
  176.         {
  177.             return instance._stringKeyedStringsLookup.ContainsKey(key);
  178.         }
  179.  
  180.         /// <summary>
  181.         /// Returns a bool indicating that the key exists in the database.
  182.         /// </summary>
  183.         public static bool HasString(int key)
  184.         {
  185.             return instance._intKeyedStringsLookup.ContainsKey(key);
  186.         }
  187.  
  188.         /// <summary>
  189.         /// Returns the string stored for the given key, if any.
  190.         /// </summary>
  191.         public static string GetString(string key)
  192.         {
  193.             if (instance._stringKeyedStringsLookup.ContainsKey(key))
  194.                 return instance._stringKeyedStringsLookup[key];
  195.  
  196.             return default(string);
  197.         }
  198.  
  199.         /// <summary>
  200.         /// Returns the string stored for the given key, if any.
  201.         /// </summary>
  202.         public static string GetString(int key)
  203.         {
  204.             if (instance._intKeyedStringsLookup.ContainsKey(key))
  205.                 return instance._intKeyedStringsLookup[key];
  206.  
  207.             return default(string);
  208.         }
  209.  
  210.         /// <summary>
  211.         /// Sets the string value to the given key.
  212.         /// </summary>
  213.         public static void SetString(string key, string value)
  214.         {
  215.             var kvp = instance._stringKeyedStrings.FirstOrDefault(t => t.Key.Equals(key));
  216.             if (kvp != null)
  217.             {
  218.                 if (kvp.Value != value)
  219.                 {
  220.                     kvp.Value = value;
  221.                     instance._dirty = true;
  222.                 }
  223.             }
  224.             else
  225.             {
  226.                 instance._stringKeyedStrings.Add(new StringStringKVP(key, value));
  227.                 instance._dirty = true;
  228.             }
  229.             instance._stringKeyedStringsLookup[key] = value;
  230.         }
  231.  
  232.         /// <summary>
  233.         /// Sets the string value to the given key.
  234.         /// </summary>
  235.         public static void SetString(int key, string value)
  236.         {
  237.             var kvp = instance._intKeyedStrings.FirstOrDefault(t => t.Key.Equals(key));
  238.             if (kvp != null)
  239.             {
  240.                 if (kvp.Value != value)
  241.                 {
  242.                     kvp.Value = value;
  243.                     instance._dirty = true;
  244.                 }
  245.             }
  246.             else
  247.             {
  248.                 instance._intKeyedStrings.Add(new IntStringKVP(key, value));
  249.                 instance._dirty = true;
  250.             }
  251.             instance._intKeyedStringsLookup[key] = value;
  252.         }
  253.  
  254.         /// <summary>
  255.         /// Returns a bool indicating that the key exists in the database.
  256.         /// </summary>
  257.         public static bool HasInt(string key)
  258.         {
  259.             return instance._stringKeyedIntsLookup.ContainsKey(key);
  260.         }
  261.  
  262.         /// <summary>
  263.         /// Returns a bool indicating that the key exists in the database.
  264.         /// </summary>
  265.         public static bool HasInt(int key)
  266.         {
  267.             return instance._intKeyedIntsLookup.ContainsKey(key);
  268.         }
  269.  
  270.         /// <summary>
  271.         /// Returns the int stored for the given key, if any.
  272.         /// </summary>
  273.         public static int GetInt(string key)
  274.         {
  275.             if (instance._stringKeyedIntsLookup.ContainsKey(key))
  276.                 return instance._stringKeyedIntsLookup[key];
  277.  
  278.             return default(int);
  279.         }
  280.  
  281.         /// <summary>
  282.         /// Returns the int stored for the given key, if any.
  283.         /// </summary>
  284.         public static int GetInt(int key)
  285.         {
  286.             if (instance._intKeyedIntsLookup.ContainsKey(key))
  287.                 return instance._intKeyedIntsLookup[key];
  288.  
  289.             return default(int);
  290.         }
  291.  
  292.         /// <summary>
  293.         /// Sets the int value to the given key.
  294.         /// </summary>
  295.         public static void SetInt(string key, int value)
  296.         {
  297.             var kvp = instance._stringKeyedInts.FirstOrDefault(t => t.Key.Equals(key));
  298.             if (kvp != null)
  299.             {
  300.                 if (kvp.Value != value)
  301.                 {
  302.                     kvp.Value = value;
  303.                     instance._dirty = true;
  304.                 }
  305.             }
  306.             else
  307.             {
  308.                 instance._stringKeyedInts.Add(new StringIntKVP(key, value));
  309.                 instance._dirty = true;
  310.             }
  311.             instance._stringKeyedIntsLookup[key] = value;
  312.         }
  313.  
  314.         /// <summary>
  315.         /// Sets the int value to the given key.
  316.         /// </summary>
  317.         public static void SetInt(int key, int value)
  318.         {
  319.             var kvp = instance._intKeyedInts.FirstOrDefault(t => t.Key.Equals(key));
  320.             if (kvp != null)
  321.             {
  322.                 if (kvp.Value != value)
  323.                 {
  324.                     kvp.Value = value;
  325.                     instance._dirty = true;
  326.                 }
  327.             }
  328.             else
  329.             {
  330.                 instance._intKeyedInts.Add(new IntIntKVP(key, value));
  331.                 instance._dirty = true;
  332.             }
  333.             instance._intKeyedIntsLookup[key] = value;
  334.         }
  335.  
  336.         /// <summary>
  337.         /// Returns a bool indicating that the key exists in the database.
  338.         /// </summary>
  339.         public static bool HasFloat(string key)
  340.         {
  341.             return instance._stringKeyedFloatsLookup.ContainsKey(key);
  342.         }
  343.  
  344.         /// <summary>
  345.         /// Returns a bool indicating that the key exists in the database.
  346.         /// </summary>
  347.         public static bool HasFloat(int key)
  348.         {
  349.             return instance._intKeyedFloatsLookup.ContainsKey(key);
  350.         }
  351.  
  352.         /// <summary>
  353.         /// Returns the float stored for the given key, if any.
  354.         /// </summary>
  355.         public static float GetFloat(string key)
  356.         {
  357.             if (instance._stringKeyedFloatsLookup.ContainsKey(key))
  358.                 return instance._stringKeyedFloatsLookup[key];
  359.  
  360.             return default(float);
  361.         }
  362.  
  363.         /// <summary>
  364.         /// Returns the float stored for the given key, if any.
  365.         /// </summary>
  366.         public static float GetFloat(int key)
  367.         {
  368.             if (instance._intKeyedFloatsLookup.ContainsKey(key))
  369.                 return instance._intKeyedFloatsLookup[key];
  370.  
  371.             return default(float);
  372.         }
  373.  
  374.         /// <summary>
  375.         /// Sets the float value to the given key.
  376.         /// </summary>
  377.         public static void SetFloat(string key, float value)
  378.         {
  379.             var kvp = instance._stringKeyedFloats.FirstOrDefault(t => t.Key.Equals(key));
  380.             if (kvp != null)
  381.             {
  382.                 if (kvp.Value != value)
  383.                 {
  384.                     kvp.Value = value;
  385.                     instance._dirty = true;
  386.                 }
  387.             }
  388.             else
  389.             {
  390.                 instance._stringKeyedFloats.Add(new StringFloatKVP(key, value));
  391.                 instance._dirty = true;
  392.             }
  393.             instance._stringKeyedFloatsLookup[key] = value;
  394.         }
  395.  
  396.         /// <summary>
  397.         /// Sets the float value to the given key.
  398.         /// </summary>
  399.         public static void SetFloat(int key, float value)
  400.         {
  401.             var kvp = instance._intKeyedFloats.FirstOrDefault(t => t.Key.Equals(key));
  402.             if (kvp != null)
  403.             {
  404.                 if (kvp.Value != value)
  405.                 {
  406.                     kvp.Value = value;
  407.                     instance._dirty = true;
  408.                 }
  409.             }
  410.             else
  411.             {
  412.                 instance._intKeyedFloats.Add(new IntFloatKVP(key, value));
  413.                 instance._dirty = true;
  414.             }
  415.             instance._intKeyedFloatsLookup[key] = value;
  416.         }
  417.  
  418.         /// <summary>
  419.         /// Returns a bool indicating that the key exists in the database.
  420.         /// </summary>
  421.         public static bool HasBool(string key)
  422.         {
  423.             return instance._stringKeyedBoolsLookup.ContainsKey(key);
  424.         }
  425.  
  426.         /// <summary>
  427.         /// Returns a bool indicating that the key exists in the database.
  428.         /// </summary>
  429.         public static bool HasBool(int key)
  430.         {
  431.             return instance._intKeyedBoolsLookup.ContainsKey(key);
  432.         }
  433.  
  434.         /// <summary>
  435.         /// Returns the bool stored for the given key, if any.
  436.         /// </summary>
  437.         public static bool GetBool(string key)
  438.         {
  439.             if (instance._stringKeyedBoolsLookup.ContainsKey(key))
  440.                 return instance._stringKeyedBoolsLookup[key];
  441.  
  442.             return default(bool);
  443.         }
  444.  
  445.         /// <summary>
  446.         /// Returns the bool stored for the given key, if any.
  447.         /// </summary>
  448.         public static bool GetBool(int key)
  449.         {
  450.             if (instance._intKeyedBoolsLookup.ContainsKey(key))
  451.                 return instance._intKeyedBoolsLookup[key];
  452.  
  453.             return default(bool);
  454.         }
  455.  
  456.         /// <summary>
  457.         /// Sets the bool value to the given key.
  458.         /// </summary>
  459.         public static void SetBool(string key, bool value)
  460.         {
  461.             var kvp = instance._stringKeyedBools.FirstOrDefault(t => t.Key.Equals(key));
  462.             if (kvp != null)
  463.             {
  464.                 if (kvp.Value != value)
  465.                 {
  466.                     kvp.Value = value;
  467.                     instance._dirty = true;
  468.                 }
  469.             }
  470.             else
  471.             {
  472.                 instance._stringKeyedBools.Add(new StringBoolKVP(key, value));
  473.                 instance._dirty = true;
  474.             }
  475.             instance._stringKeyedBoolsLookup[key] = value;
  476.         }
  477.  
  478.         /// <summary>
  479.         /// Sets the bool value to the given key.
  480.         /// </summary>
  481.         public static void SetBool(int key, bool value)
  482.         {
  483.             var kvp = instance._intKeyedBools.FirstOrDefault(t => t.Key.Equals(key));
  484.             if (kvp != null)
  485.             {
  486.                 if (kvp.Value != value)
  487.                 {
  488.                     kvp.Value = value;
  489.                     instance._dirty = true;
  490.                 }
  491.             }
  492.             else
  493.             {
  494.                 instance._intKeyedBools.Add(new IntBoolKVP(key, value));
  495.                 instance._dirty = true;
  496.             }
  497.             instance._intKeyedBoolsLookup[key] = value;
  498.         }
  499.  
  500.  
  501.         /// <summary>
  502.         /// Loads LocalPrefs from a file location and returns it.
  503.         /// </summary>
  504.         public static LocalPrefs LoadPrefsFromFile(string path)
  505.         {
  506.             try
  507.             {
  508.                 byte[] byteArray = File.ReadAllBytes(path);
  509.  
  510.                 BinaryFormatter bf = new BinaryFormatter();
  511.                 using (MemoryStream ms = new MemoryStream(byteArray))
  512.                 {
  513.                     return (LocalPrefs)bf.Deserialize(ms);
  514.                 }
  515.             }
  516.             catch
  517.             {
  518.  
  519.             }
  520.             return null;
  521.         }
  522.  
  523.         /// <summary>
  524.         /// Saves LocalPrefs to a file location.
  525.         /// </summary>
  526.         public static void SavePrefsToFile(LocalPrefs prefsToSave, string path)
  527.         {
  528.             if (prefsToSave._dirty)
  529.             {
  530.                 try
  531.                 {
  532.                     BinaryFormatter bf = new BinaryFormatter();
  533.                     using (MemoryStream ms = new MemoryStream())
  534.                     {
  535.                         bf.Serialize(ms, prefsToSave);
  536.                         byte[] byteArray = ms.ToArray();
  537.  
  538.                         using (var file = File.Open(path, FileMode.Create))
  539.                         {
  540.                             var binary = new BinaryWriter(file);
  541.                             binary.Write(prefsToSave);
  542.                         }
  543.                     }
  544.                 }
  545.                 catch
  546.                 {
  547.  
  548.                 }
  549.                 prefsToSave._dirty = false;
  550.             }
  551.         }
  552.  
  553.  
  554.         // this garbage is required for serializing the lists properly, because reasons
  555.         [System.Serializable]
  556.         private class StringStringKVP : KVP<string, string>
  557.         {
  558.             public StringStringKVP(string key, string value)
  559.                 : base(key, value) { }
  560.         }
  561.         [System.Serializable]
  562.         private class StringIntKVP : KVP<string, int>
  563.         {
  564.             public StringIntKVP(string key, int value)
  565.                 : base(key, value) { }
  566.         }
  567.         [System.Serializable]
  568.         private class StringFloatKVP : KVP<string, float>
  569.         {
  570.             public StringFloatKVP(string key, float value)
  571.                 : base(key, value) { }
  572.         }
  573.         [System.Serializable]
  574.         private class StringBoolKVP : KVP<string, bool>
  575.         {
  576.             public StringBoolKVP(string key, bool value)
  577.                 : base(key, value) { }
  578.         }
  579.         [System.Serializable]
  580.         private class IntStringKVP : KVP<int, string>
  581.         {
  582.             public IntStringKVP(int key, string value)
  583.                 : base(key, value) { }
  584.         }
  585.         [System.Serializable]
  586.         private class IntIntKVP : KVP<int, int>
  587.         {
  588.             public IntIntKVP(int key, int value)
  589.                 : base(key, value) { }
  590.         }
  591.         [System.Serializable]
  592.         private class IntFloatKVP : KVP<int, float>
  593.         {
  594.             public IntFloatKVP(int key, float value)
  595.                 : base(key, value) { }
  596.         }
  597.         [System.Serializable]
  598.         private class IntBoolKVP : KVP<int, bool>
  599.         {
  600.             public IntBoolKVP(int key, bool value)
  601.                 : base(key, value) { }
  602.         }
  603.  
  604.         /// <summary>
  605.         /// Base "KeyValuePair" serializable class for prefs collections
  606.         /// </summary>
  607.         [System.Serializable]
  608.         private class KVP<T1, T2> : System.IEquatable<KVP<T1, T2>>
  609.         {
  610.             public T1 Key;
  611.             public T2 Value;
  612.  
  613.  
  614.             public KVP(T1 key, T2 value)
  615.             {
  616.                 this.Key = key;
  617.                 this.Value = value;
  618.             }
  619.  
  620.  
  621.             public override int GetHashCode()
  622.             {
  623.                 unchecked { return Key.GetHashCode() + Value.GetHashCode(); }
  624.             }
  625.  
  626.             public override bool Equals(object obj)
  627.             {
  628.                 if (typeof(KVP<T1, T2>).IsAssignableFrom(obj.GetType()))
  629.                     return this.Equals((KVP<T1, T2>)obj);
  630.  
  631.                 return false;
  632.             }
  633.  
  634.             public bool Equals(KVP<T1, T2> other)
  635.             {
  636.                 return Key.Equals(other.Key) && Value.Equals(other.Value);
  637.             }
  638.         }
  639.     }
  640. }
Advertisement
Add Comment
Please, Sign In to add comment