From 51aff758045adabaf17c603a51cf02b78ac62f98 Mon Sep 17 00:00:00 2001 From: Patrick Martin Date: Fri, 8 Aug 2014 11:10:04 -0600 Subject: [PATCH] Added a way to load levels on a thread other than the Unity thread safely (namely for Sphero streaming callbbacks). --- .../Plugins/Sphero/NoSpheroConnectedView.cs | 17 +++- .../Plugins/Sphero/SpheroConnectionView.cs | 22 ++++- .../Plugins/Sphero/ThreadSafeLoadLevel.cs | 82 ++++++++++++++++++ .../Sphero/ThreadSafeLoadLevel.cs.meta | 8 ++ .../Plugins/Sphero/NoSpheroConnectedView.cs | 17 +++- .../Plugins/Sphero/SpheroConnectionView.cs | 22 ++++- .../Plugins/Sphero/ThreadSafeLoadLevel.cs | 82 ++++++++++++++++++ .../Sphero/ThreadSafeLoadLevel.cs.meta | 8 ++ .../Assets/Scripts/UpdateValues.cs | 21 ++++- .../ProjectSettings/ProjectSettings.asset | Bin 12116 -> 24828 bytes .../Plugins/Sphero/NoSpheroConnectedView.cs | 17 +++- .../Plugins/Sphero/SpheroConnectionView.cs | 22 ++++- .../Plugins/Sphero/ThreadSafeLoadLevel.cs | 82 ++++++++++++++++++ .../Sphero/ThreadSafeLoadLevel.cs.meta | 8 ++ Plugins/Sphero/NoSpheroConnectedView.cs | 17 +++- Plugins/Sphero/SpheroConnectionView.cs | 22 ++++- Plugins/Sphero/ThreadSafeLoadLevel.cs | 82 ++++++++++++++++++ Plugins/Sphero/ThreadSafeLoadLevel.cs.meta | 8 ++ 18 files changed, 514 insertions(+), 23 deletions(-) create mode 100644 ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs create mode 100644 ExampleProject/HelloWorld/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta create mode 100644 ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs create mode 100644 ExampleProject/SensorStreaming/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta create mode 100644 ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs create mode 100644 ExampleProject/UISample/Assets/Plugins/Sphero/ThreadSafeLoadLevel.cs.meta create mode 100644 Plugins/Sphero/ThreadSafeLoadLevel.cs create mode 100644 Plugins/Sphero/ThreadSafeLoadLevel.cs.meta 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 a8e33944794798be9bee5e9fb29d51547d6b41d5..789ae6b1a87b1805be64ec318c7bc3f5130d959d 100644 GIT binary patch literal 24828 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 E0a>~qy#N3J 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: