aboutsummaryrefslogtreecommitdiff
path: root/Assets/Packages/Tayx/Graphy - Ultimate Stats Monitor/Scripts/Util/G_Singleton.cs
blob: 5feaa7a28cdce88ffd25ee1ba1da6779012711eb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/* ---------------------------------------
 * Sourced from:    https://wiki.unity3d.com/index.php/Singleton
 * Modified by:     Martín Pane (martintayx@gmail.com) (@tayx94)
 * Collaborators:   Lars Aalbertsen (@Rockylars)
 * Project:         Graphy - Ultimate Stats Monitor
 * Date:            07-Jul-17
 * Studio:          Tayx
 * 
 * This project is released under the MIT license.
 * Attribution is not required, but it is always welcomed!
 * -------------------------------------*/

using UnityEngine;

namespace Tayx.Graphy.Utils
{
    /// <summary>
    /// Be aware this will not prevent a non singleton constructor
    ///   such as `T myT = new T();`
    /// To prevent that, add `protected T () {}` to your singleton class.
    /// 
    /// As a note, this is made as MonoBehaviour because we need Coroutines.
    /// </summary>
    public class G_Singleton<T> : MonoBehaviour where T : MonoBehaviour
    {
        /* ----- TODO: ----------------------------
         * Check if we can seal this class.
         * Add summaries to the variables.
         * Add summaries to the functions.
         * Check if we should add "private" to the Unity Callbacks.
         * Fill in the missing date and author.
         * --------------------------------------*/

        #region Variables -> Private

        private static  T       _instance;

        private static  object  _lock       = new object();

        #endregion

        #region Properties -> Public

        public static T Instance
        {
            get
            {
                
                if (_applicationIsQuitting)
                {
                    //Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
                    //    "' already destroyed on application quit." +
                    //    " Won't create again - returning null.");
                    return null;
                }
                
                lock (_lock)
                {
                    if (_instance == null)
                    {
                        _instance = (T)FindObjectOfType(typeof(T));

                        if (FindObjectsOfType(typeof(T)).Length > 1)
                        {
                            //Debug.LogError("[Singleton] Something went really wrong " +
                            //    " - there should never be more than 1 singleton!" +
                            //    " Reopening the scene might fix it.");
                            return _instance;
                        }

                        if (_instance == null)
                        {
                            //GameObject singleton = new GameObject();
                            //_instance = singleton.AddComponent<T>();
                            //singleton.name = "(singleton) " + typeof(T).ToString();

                            //DontDestroyOnLoad(singleton);

                            //Debug.Log("[Singleton] An instance of " + typeof(T) +
                            //    " is needed in the scene, so '" + singleton +
                            //    "' was created with DontDestroyOnLoad.");

                            Debug.Log
                            (
                                "[Singleton] An instance of " + typeof(T) +
                                " is trying to be accessed, but it wasn't initialized first. " +
                                "Make sure to add an instance of " + typeof(T) + " in the scene before " +
                                " trying to access it."
                            );
                        }
                        else
                        {
                            //Debug.Log("[Singleton] Using instance already created: " +
                            //    _instance.gameObject.name);
                        }
                    }

                    return _instance;
                }
            }
        }

        #endregion

        #region Methods -> Unity Callbacks

        void Awake()
        {
            if (_instance != null)
            {
                Destroy(gameObject);
            }
            else
            {
                _instance = GetComponent<T>();
            }
        }

        private static bool _applicationIsQuitting = false;
        /// <summary>
        /// When Unity quits, it destroys objects in a random order.
        /// In principle, a Singleton is only destroyed when application quits.
        /// If any script calls Instance after it has been destroyed, 
        ///   it will create a buggy ghost object that will stay on the Editor scene
        ///   even after stopping playing the Application. Really bad!
        /// So, this was made to be sure we're not creating that buggy ghost object.
        /// </summary>
        void OnDestroy()
        {
            _applicationIsQuitting = true;
        }

        #endregion
    }
}