You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

172 lines
5.5 KiB

/**
* Copyright 2015 IBM Corp. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
// Uncomment to enable debugging of the Runnable class.
//#define ENABLE_RUNNABLE_DEBUGGING
namespace Mapbox.Unity.Utilities
{
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/// <summary>
/// Helper class for running co-routines without having to inherit from MonoBehavior.
/// </summary>
public class Runnable : MonoBehaviour
{
#region Public Properties
/// <summary>
/// Returns the Runnable instance.
/// </summary>
public static Runnable Instance { get { return Singleton<Runnable>.Instance; } }
#endregion
#region Public Interface
/// <summary>
/// Start a co-routine function.
/// </summary>
/// <param name="routine">The IEnumerator returns by the co-routine function the user is invoking.</param>
/// <returns>Returns a ID that can be passed into Stop() to halt the co-routine.</returns>
public static int Run(IEnumerator routine)
{
Routine r = new Routine(routine);
return r.ID;
}
/// <summary>
/// Stops a active co-routine.
/// </summary>
/// <param name="ID">THe ID of the co-routine to stop.</param>
public static void Stop(int ID)
{
Routine r = null;
if (Instance.m_Routines.TryGetValue(ID, out r))
r.Stop = true;
}
/// <summary>
/// Check if a routine is still running.
/// </summary>
/// <param name="id">The ID returned by Run().</param>
/// <returns>Returns true if the routine is still active.</returns>
static public bool IsRunning(int id)
{
return Instance.m_Routines.ContainsKey(id);
}
#if UNITY_EDITOR
private static bool sm_EditorRunnable = false;
/// <summary>
/// This function enables the Runnable in edit mode.
/// </summary>
public static void EnableRunnableInEditor()
{
if (!sm_EditorRunnable)
{
sm_EditorRunnable = true;
UnityEditor.EditorApplication.update += UpdateRunnable;
}
}
static void UpdateRunnable()
{
if (!Application.isPlaying)
{
Instance.UpdateRoutines();
}
}
#endif
#endregion
#region Private Types
/// <summary>
/// This class handles a running co-routine.
/// </summary>
private class Routine : IEnumerator
{
#region Public Properties
public int ID { get; private set; }
public bool Stop { get; set; }
#endregion
#region Private Data
private bool m_bMoveNext = false;
private IEnumerator m_Enumerator = null;
#endregion
public Routine(IEnumerator a_enumerator)
{
m_Enumerator = a_enumerator;
Runnable.Instance.StartCoroutine(this);
Stop = false;
ID = Runnable.Instance.m_NextRoutineId++;
Runnable.Instance.m_Routines[ID] = this;
#if ENABLE_RUNNABLE_DEBUGGING
Debug.Log( string.Format("Coroutine {0} started.", ID ) );
#endif
}
#region IEnumerator Interface
public object Current { get { return m_Enumerator.Current; } }
public bool MoveNext()
{
m_bMoveNext = m_Enumerator.MoveNext();
if (m_bMoveNext && Stop)
m_bMoveNext = false;
if (!m_bMoveNext)
{
Runnable.Instance.m_Routines.Remove(ID); // remove from the mapping
#if ENABLE_RUNNABLE_DEBUGGING
Debug.Log( string.Format("Coroutine {0} stopped.", ID ) );
#endif
}
return m_bMoveNext;
}
public void Reset() { m_Enumerator.Reset(); }
#endregion
}
#endregion
#region Private Data
private Dictionary<int, Routine> m_Routines = new Dictionary<int, Routine>();
private int m_NextRoutineId = 1;
#endregion
/// <summary>
/// THis can be called by the user to force all co-routines to get a time slice, this is usually
/// invoked from an EditorApplication.Update callback so we can use runnable in Editor mode.
/// </summary>
public void UpdateRoutines()
{
if (m_Routines.Count > 0)
{
// we are not in play mode, so we must manually update our co-routines ourselves
List<Routine> routines = new List<Routine>();
foreach (var kp in m_Routines)
routines.Add(kp.Value);
foreach (var r in routines)
r.MoveNext();
}
}
}
}