diff --git a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/NoSpheroConnectedView.cs b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/NoSpheroConnectedView.cs index cb3c09e..61a67d6 100644 --- a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/NoSpheroConnectedView.cs +++ b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/NoSpheroConnectedView.cs @@ -27,6 +27,13 @@ public class NoSpheroConnectedView : MonoBehaviour { // UI Padding Variables int m_ViewPadding = 20; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } void Start () { ViewSetup(); @@ -59,7 +66,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes SpheroDeviceNotification message = (SpheroDeviceNotification)eventArgs.Message; if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTED ) { // Go to the desired scene - Application.LoadLevel (m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } @@ -125,7 +135,10 @@ void OnGUI() { getASpheroButtonY = backgroundY+(backgroundHeight*0.85f) - (buttonHeight/2); // If the get a Sphero button is clicked if( GUI.Button (new Rect(getASpheroButtonX, getASpheroButtonY,buttonWidth,buttonHeight), "") ) { - Application.LoadLevel("SpheroConnectionScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("SpheroConnectionScene"); + } } #endif } diff --git a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/SpheroConnectionView.cs b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/SpheroConnectionView.cs index 82effdc..eef8666 100644 --- a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/SpheroConnectionView.cs +++ b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/SpheroConnectionView.cs @@ -60,6 +60,8 @@ public class SpheroConnectionView : MonoBehaviour { Vector2 windowMargin = new Vector2(0,0); Vector2 listMargin = new Vector2(40,40); private Rect windowRect; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; /* Use this to initialize the view */ private void ViewSetup() { @@ -72,6 +74,11 @@ private void ViewSetup() { // Display that it doesn't work with these platforms? #endif } + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } /* Use these for initialization */ void Start () { @@ -106,7 +113,10 @@ void SetupIOS() { */ void CheckForSpheroConnection() { if( m_SpheroProvider.GetConnectedSpheros().Length == 0 ) { - Application.LoadLevel("NoSpheroConnectedScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("NoSpheroConnectedScene"); + } } } @@ -157,7 +167,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes if( !m_MultipleSpheros ) { m_Title = "Connection Success"; SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } else if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTION_FAILED ) { @@ -281,7 +294,10 @@ void OnGUI() { // Check if we are done adding robots if( buttonLabel.Equals("Done") ){ SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } // Check if we have a Sphero connected else if( m_SpheroLabelSelected >= 0 ) { diff --git a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs new file mode 100644 index 0000000..fc2426e --- /dev/null +++ b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs @@ -0,0 +1,82 @@ +using System.Threading; +using UnityEngine; + +/// +/// The goal of this class is to let you load levels (from the Sphero callbacks) in a way that +/// doesn't try to make Unity calls on a thread other than the Unity thread. Unity takes issue with +/// this and will throw a crashing-tantrum. +/// +public class ThreadSafeLoadLevel : MonoBehaviour +{ + #region Static instance management + /// + /// Static instance of this script + /// + private static ThreadSafeLoadLevel s_instance; + + /// + /// No creating an instance after OnApplicationQuit is called - can get funky in the editor + /// + private static bool m_exiting; + + /// + /// Gets the static instance of his script. This is *NOT* thread safe. Call it from Unity's + /// thread (creates a Unity object) + /// + public static ThreadSafeLoadLevel Instance + { + get + { + if (s_instance == null && !m_exiting) + { + var go = new GameObject("ThreadSafeLoadLevel"); + s_instance = go.AddComponent(); + } + return s_instance; + } + } + #endregion + + /// + /// An object to lock on + /// + private readonly Object m_lock = new Object(); + + /// + /// The level we want to load + /// + private string m_levelToLoad; + + #region Unity-style callbacks + void Update() + { + // non-blocking lock acquire + if (Monitor.TryEnter(m_lock)) + { + if (!string.IsNullOrEmpty(m_levelToLoad)) + { + Application.LoadLevel(m_levelToLoad); + } + + Monitor.Exit(m_lock); + } + } + + void OnApplicationQuit() + { + m_exiting = true; + } + #endregion + + /// + /// Loads the given level by name + /// + /// a level we wish to load + public void LoadLevel(string levelName) + { + lock (m_lock) + { + m_levelToLoad = levelName; + } + } +} diff --git a/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta new file mode 100644 index 0000000..0cca37d --- /dev/null +++ b/ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51bc1e102d852f54ba6e77fee637e2d6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/NoSpheroConnectedView.cs b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/NoSpheroConnectedView.cs index cb3c09e..61a67d6 100644 --- a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/NoSpheroConnectedView.cs +++ b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/NoSpheroConnectedView.cs @@ -27,6 +27,13 @@ public class NoSpheroConnectedView : MonoBehaviour { // UI Padding Variables int m_ViewPadding = 20; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } void Start () { ViewSetup(); @@ -59,7 +66,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes SpheroDeviceNotification message = (SpheroDeviceNotification)eventArgs.Message; if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTED ) { // Go to the desired scene - Application.LoadLevel (m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } @@ -125,7 +135,10 @@ void OnGUI() { getASpheroButtonY = backgroundY+(backgroundHeight*0.85f) - (buttonHeight/2); // If the get a Sphero button is clicked if( GUI.Button (new Rect(getASpheroButtonX, getASpheroButtonY,buttonWidth,buttonHeight), "") ) { - Application.LoadLevel("SpheroConnectionScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("SpheroConnectionScene"); + } } #endif } diff --git a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/SpheroConnectionView.cs b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/SpheroConnectionView.cs index 82effdc..eef8666 100644 --- a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/SpheroConnectionView.cs +++ b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/SpheroConnectionView.cs @@ -60,6 +60,8 @@ public class SpheroConnectionView : MonoBehaviour { Vector2 windowMargin = new Vector2(0,0); Vector2 listMargin = new Vector2(40,40); private Rect windowRect; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; /* Use this to initialize the view */ private void ViewSetup() { @@ -72,6 +74,11 @@ private void ViewSetup() { // Display that it doesn't work with these platforms? #endif } + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } /* Use these for initialization */ void Start () { @@ -106,7 +113,10 @@ void SetupIOS() { */ void CheckForSpheroConnection() { if( m_SpheroProvider.GetConnectedSpheros().Length == 0 ) { - Application.LoadLevel("NoSpheroConnectedScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("NoSpheroConnectedScene"); + } } } @@ -157,7 +167,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes if( !m_MultipleSpheros ) { m_Title = "Connection Success"; SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } else if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTION_FAILED ) { @@ -281,7 +294,10 @@ void OnGUI() { // Check if we are done adding robots if( buttonLabel.Equals("Done") ){ SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } // Check if we have a Sphero connected else if( m_SpheroLabelSelected >= 0 ) { diff --git a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs new file mode 100644 index 0000000..fc2426e --- /dev/null +++ b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs @@ -0,0 +1,82 @@ +using System.Threading; +using UnityEngine; + +/// +/// The goal of this class is to let you load levels (from the Sphero callbacks) in a way that +/// doesn't try to make Unity calls on a thread other than the Unity thread. Unity takes issue with +/// this and will throw a crashing-tantrum. +/// +public class ThreadSafeLoadLevel : MonoBehaviour +{ + #region Static instance management + /// + /// Static instance of this script + /// + private static ThreadSafeLoadLevel s_instance; + + /// + /// No creating an instance after OnApplicationQuit is called - can get funky in the editor + /// + private static bool m_exiting; + + /// + /// Gets the static instance of his script. This is *NOT* thread safe. Call it from Unity's + /// thread (creates a Unity object) + /// + public static ThreadSafeLoadLevel Instance + { + get + { + if (s_instance == null && !m_exiting) + { + var go = new GameObject("ThreadSafeLoadLevel"); + s_instance = go.AddComponent(); + } + return s_instance; + } + } + #endregion + + /// + /// An object to lock on + /// + private readonly Object m_lock = new Object(); + + /// + /// The level we want to load + /// + private string m_levelToLoad; + + #region Unity-style callbacks + void Update() + { + // non-blocking lock acquire + if (Monitor.TryEnter(m_lock)) + { + if (!string.IsNullOrEmpty(m_levelToLoad)) + { + Application.LoadLevel(m_levelToLoad); + } + + Monitor.Exit(m_lock); + } + } + + void OnApplicationQuit() + { + m_exiting = true; + } + #endregion + + /// + /// Loads the given level by name + /// + /// a level we wish to load + public void LoadLevel(string levelName) + { + lock (m_lock) + { + m_levelToLoad = levelName; + } + } +} diff --git a/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta new file mode 100644 index 0000000..0cca37d --- /dev/null +++ b/ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51bc1e102d852f54ba6e77fee637e2d6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/ExampleProject/SensorStreaming/Assets/Scripts/UpdateValues.cs b/ExampleProject/SensorStreaming/Assets/Scripts/UpdateValues.cs index efcaae0..06630dc 100644 --- a/ExampleProject/SensorStreaming/Assets/Scripts/UpdateValues.cs +++ b/ExampleProject/SensorStreaming/Assets/Scripts/UpdateValues.cs @@ -18,14 +18,26 @@ public class UpdateValues: MonoBehaviour { private float q1 = 1.0f; private float q2 = 1.0f; private float q3 = 1.0f; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; /* Use this for initialization */ void ViewSetup() { // Get Connected Sphero SpheroDeviceMessenger.SharedInstance.NotificationReceived += ReceiveNotificationMessage; - if( SpheroProvider.GetSharedProvider().GetConnectedSpheros().Length == 0 ) - Application.LoadLevel("SpheroConnectionScene"); + if (SpheroProvider.GetSharedProvider().GetConnectedSpheros().Length == 0) + { + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("SpheroConnectionScene"); + } + } + } + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; } // Use this for initialization @@ -132,7 +144,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.DISCONNECTED ) { notifiedSphero.ConnectionState = Sphero.Connection_State.Disconnected; streaming = false; - Application.LoadLevel("NoSpheroConnectedScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("NoSpheroConnectedScene"); + } } } } diff --git a/ExampleProject/SensorStreaming/ProjectSettings/ProjectSettings.asset b/ExampleProject/SensorStreaming/ProjectSettings/ProjectSettings.asset index a8e3394..789ae6b 100644 Binary files a/ExampleProject/SensorStreaming/ProjectSettings/ProjectSettings.asset and b/ExampleProject/SensorStreaming/ProjectSettings/ProjectSettings.asset differ diff --git a/ExampleProject/UISample/Assets/Plugins/Sphero/NoSpheroConnectedView.cs b/ExampleProject/UISample/Assets/Plugins/Sphero/NoSpheroConnectedView.cs index cb3c09e..61a67d6 100644 --- a/ExampleProject/UISample/Assets/Plugins/Sphero/NoSpheroConnectedView.cs +++ b/ExampleProject/UISample/Assets/Plugins/Sphero/NoSpheroConnectedView.cs @@ -27,6 +27,13 @@ public class NoSpheroConnectedView : MonoBehaviour { // UI Padding Variables int m_ViewPadding = 20; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } void Start () { ViewSetup(); @@ -59,7 +66,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes SpheroDeviceNotification message = (SpheroDeviceNotification)eventArgs.Message; if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTED ) { // Go to the desired scene - Application.LoadLevel (m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } @@ -125,7 +135,10 @@ void OnGUI() { getASpheroButtonY = backgroundY+(backgroundHeight*0.85f) - (buttonHeight/2); // If the get a Sphero button is clicked if( GUI.Button (new Rect(getASpheroButtonX, getASpheroButtonY,buttonWidth,buttonHeight), "") ) { - Application.LoadLevel("SpheroConnectionScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("SpheroConnectionScene"); + } } #endif } diff --git a/ExampleProject/UISample/Assets/Plugins/Sphero/SpheroConnectionView.cs b/ExampleProject/UISample/Assets/Plugins/Sphero/SpheroConnectionView.cs index 82effdc..eef8666 100644 --- a/ExampleProject/UISample/Assets/Plugins/Sphero/SpheroConnectionView.cs +++ b/ExampleProject/UISample/Assets/Plugins/Sphero/SpheroConnectionView.cs @@ -60,6 +60,8 @@ public class SpheroConnectionView : MonoBehaviour { Vector2 windowMargin = new Vector2(0,0); Vector2 listMargin = new Vector2(40,40); private Rect windowRect; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; /* Use this to initialize the view */ private void ViewSetup() { @@ -72,6 +74,11 @@ private void ViewSetup() { // Display that it doesn't work with these platforms? #endif } + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } /* Use these for initialization */ void Start () { @@ -106,7 +113,10 @@ void SetupIOS() { */ void CheckForSpheroConnection() { if( m_SpheroProvider.GetConnectedSpheros().Length == 0 ) { - Application.LoadLevel("NoSpheroConnectedScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("NoSpheroConnectedScene"); + } } } @@ -157,7 +167,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes if( !m_MultipleSpheros ) { m_Title = "Connection Success"; SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } else if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTION_FAILED ) { @@ -281,7 +294,10 @@ void OnGUI() { // Check if we are done adding robots if( buttonLabel.Equals("Done") ){ SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } // Check if we have a Sphero connected else if( m_SpheroLabelSelected >= 0 ) { diff --git a/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs b/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs new file mode 100644 index 0000000..fc2426e --- /dev/null +++ b/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs @@ -0,0 +1,82 @@ +using System.Threading; +using UnityEngine; + +/// +/// The goal of this class is to let you load levels (from the Sphero callbacks) in a way that +/// doesn't try to make Unity calls on a thread other than the Unity thread. Unity takes issue with +/// this and will throw a crashing-tantrum. +/// +public class ThreadSafeLoadLevel : MonoBehaviour +{ + #region Static instance management + /// + /// Static instance of this script + /// + private static ThreadSafeLoadLevel s_instance; + + /// + /// No creating an instance after OnApplicationQuit is called - can get funky in the editor + /// + private static bool m_exiting; + + /// + /// Gets the static instance of his script. This is *NOT* thread safe. Call it from Unity's + /// thread (creates a Unity object) + /// + public static ThreadSafeLoadLevel Instance + { + get + { + if (s_instance == null && !m_exiting) + { + var go = new GameObject("ThreadSafeLoadLevel"); + s_instance = go.AddComponent(); + } + return s_instance; + } + } + #endregion + + /// + /// An object to lock on + /// + private readonly Object m_lock = new Object(); + + /// + /// The level we want to load + /// + private string m_levelToLoad; + + #region Unity-style callbacks + void Update() + { + // non-blocking lock acquire + if (Monitor.TryEnter(m_lock)) + { + if (!string.IsNullOrEmpty(m_levelToLoad)) + { + Application.LoadLevel(m_levelToLoad); + } + + Monitor.Exit(m_lock); + } + } + + void OnApplicationQuit() + { + m_exiting = true; + } + #endregion + + /// + /// Loads the given level by name + /// + /// a level we wish to load + public void LoadLevel(string levelName) + { + lock (m_lock) + { + m_levelToLoad = levelName; + } + } +} diff --git a/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta b/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta new file mode 100644 index 0000000..0cca37d --- /dev/null +++ b/ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51bc1e102d852f54ba6e77fee637e2d6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Plugins/Sphero/NoSpheroConnectedView.cs b/Plugins/Sphero/NoSpheroConnectedView.cs index cb3c09e..61a67d6 100644 --- a/Plugins/Sphero/NoSpheroConnectedView.cs +++ b/Plugins/Sphero/NoSpheroConnectedView.cs @@ -27,6 +27,13 @@ public class NoSpheroConnectedView : MonoBehaviour { // UI Padding Variables int m_ViewPadding = 20; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } void Start () { ViewSetup(); @@ -59,7 +66,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes SpheroDeviceNotification message = (SpheroDeviceNotification)eventArgs.Message; if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTED ) { // Go to the desired scene - Application.LoadLevel (m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } @@ -125,7 +135,10 @@ void OnGUI() { getASpheroButtonY = backgroundY+(backgroundHeight*0.85f) - (buttonHeight/2); // If the get a Sphero button is clicked if( GUI.Button (new Rect(getASpheroButtonX, getASpheroButtonY,buttonWidth,buttonHeight), "") ) { - Application.LoadLevel("SpheroConnectionScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("SpheroConnectionScene"); + } } #endif } diff --git a/Plugins/Sphero/SpheroConnectionView.cs b/Plugins/Sphero/SpheroConnectionView.cs index 82effdc..eef8666 100644 --- a/Plugins/Sphero/SpheroConnectionView.cs +++ b/Plugins/Sphero/SpheroConnectionView.cs @@ -60,6 +60,8 @@ public class SpheroConnectionView : MonoBehaviour { Vector2 windowMargin = new Vector2(0,0); Vector2 listMargin = new Vector2(40,40); private Rect windowRect; + + private ThreadSafeLoadLevel m_threadSafeLoadLevel; /* Use this to initialize the view */ private void ViewSetup() { @@ -72,6 +74,11 @@ private void ViewSetup() { // Display that it doesn't work with these platforms? #endif } + + void Awake() + { + m_threadSafeLoadLevel = ThreadSafeLoadLevel.Instance; + } /* Use these for initialization */ void Start () { @@ -106,7 +113,10 @@ void SetupIOS() { */ void CheckForSpheroConnection() { if( m_SpheroProvider.GetConnectedSpheros().Length == 0 ) { - Application.LoadLevel("NoSpheroConnectedScene"); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel("NoSpheroConnectedScene"); + } } } @@ -157,7 +167,10 @@ private void ReceiveNotificationMessage(object sender, SpheroDeviceMessenger.Mes if( !m_MultipleSpheros ) { m_Title = "Connection Success"; SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } } else if( message.NotificationType == SpheroDeviceNotification.SpheroNotificationType.CONNECTION_FAILED ) { @@ -281,7 +294,10 @@ void OnGUI() { // Check if we are done adding robots if( buttonLabel.Equals("Done") ){ SpheroDeviceMessenger.SharedInstance.NotificationReceived -= ReceiveNotificationMessage; - Application.LoadLevel(m_NextLevel); + if (m_threadSafeLoadLevel != null) + { + m_threadSafeLoadLevel.LoadLevel(m_NextLevel); + } } // Check if we have a Sphero connected else if( m_SpheroLabelSelected >= 0 ) { diff --git a/Plugins/Sphero/ThreadSafeLoadLevel.cs b/Plugins/Sphero/ThreadSafeLoadLevel.cs new file mode 100644 index 0000000..fc2426e --- /dev/null +++ b/Plugins/Sphero/ThreadSafeLoadLevel.cs @@ -0,0 +1,82 @@ +using System.Threading; +using UnityEngine; + +/// +/// The goal of this class is to let you load levels (from the Sphero callbacks) in a way that +/// doesn't try to make Unity calls on a thread other than the Unity thread. Unity takes issue with +/// this and will throw a crashing-tantrum. +/// +public class ThreadSafeLoadLevel : MonoBehaviour +{ + #region Static instance management + /// + /// Static instance of this script + /// + private static ThreadSafeLoadLevel s_instance; + + /// + /// No creating an instance after OnApplicationQuit is called - can get funky in the editor + /// + private static bool m_exiting; + + /// + /// Gets the static instance of his script. This is *NOT* thread safe. Call it from Unity's + /// thread (creates a Unity object) + /// + public static ThreadSafeLoadLevel Instance + { + get + { + if (s_instance == null && !m_exiting) + { + var go = new GameObject("ThreadSafeLoadLevel"); + s_instance = go.AddComponent(); + } + return s_instance; + } + } + #endregion + + /// + /// An object to lock on + /// + private readonly Object m_lock = new Object(); + + /// + /// The level we want to load + /// + private string m_levelToLoad; + + #region Unity-style callbacks + void Update() + { + // non-blocking lock acquire + if (Monitor.TryEnter(m_lock)) + { + if (!string.IsNullOrEmpty(m_levelToLoad)) + { + Application.LoadLevel(m_levelToLoad); + } + + Monitor.Exit(m_lock); + } + } + + void OnApplicationQuit() + { + m_exiting = true; + } + #endregion + + /// + /// Loads the given level by name + /// + /// a level we wish to load + public void LoadLevel(string levelName) + { + lock (m_lock) + { + m_levelToLoad = levelName; + } + } +} diff --git a/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta b/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta new file mode 100644 index 0000000..0cca37d --- /dev/null +++ b/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 51bc1e102d852f54ba6e77fee637e2d6 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: