// Copyright (c) Pixel Crushers. All rights reserved. using UnityEngine; using System.Collections; using System.Collections.Generic; namespace PixelCrushers.QuestMachine { /// /// Central manager for all timers that implement the IQuestTimer interface. /// Typically one instance of this script exists on the QuestMachineConfiguration /// instance. Every second, it invokes the timers' Tick() method. /// [AddComponentMenu("")] // Use wrapper instead. public class QuestTimerManager : MonoBehaviour { private static QuestTimerManager s_instance = null; private static QuestTimerManager instance { get { if (s_instance == null) CreateInstance(); return s_instance; } } #if UNITY_2019_3_OR_NEWER && UNITY_EDITOR [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] static void InitStaticVariables() { s_instance = null; } #endif private static QuestTimerManager CreateInstance() { if (QuestMachineConfiguration.isQuitting) return null; var attachTo = (QuestMachineConfiguration.instance != null) ? QuestMachineConfiguration.instance.gameObject : new GameObject("Quest Timer Manager"); return attachTo.GetComponent() ?? attachTo.AddComponent(); } /// /// Register a timer to receive ticks. /// /// public static void RegisterTimer(IQuestTimer timer) { if (!Application.isPlaying || QuestMachineConfiguration.isQuitting) return; instance.Register(timer); } /// /// Unregister a timer so it no longer receives ticks. /// /// public static void UnregisterTimer(IQuestTimer timer) { if (!Application.isPlaying || QuestMachineConfiguration.isQuitting) return; instance.Unregister(timer); } private List m_timers = new List(); private void Awake() { s_instance = this; } /// /// Registers a timer with this instance of QuestTimerManager. /// This method is usually called implicitly by the static method /// QuestTimerManager.RegisterTimer. /// public void Register(IQuestTimer timer) { if (timer == null || m_timers.Contains(timer)) return; m_timers.Add(timer); if (m_timers.Count == 1) { // First timer, so start coroutine: StartCoroutine(TimerCoroutine()); } } /// /// Unregisters a timer from this instance of QuestTimerManager. /// This method is usually called implicitly by the static method /// QuestTimerManager.UnregisterTimer. /// public void Unregister(IQuestTimer timer) { if (timer == null || !m_timers.Contains(timer)) return; m_timers.Remove(timer); if (m_timers.Count <= 0) { // No more timers, so stop coroutine: StopAllCoroutines(); } } private IEnumerator TimerCoroutine() { var oneSecond = new WaitForSeconds(1); while (true) { yield return oneSecond; Tick(); } } /// /// Invokes the Tick method on all registered timers. /// public void Tick() { for (int i = 0; i < m_timers.Count; i++) { if (m_timers[i] != null) { try { m_timers[i].Tick(); } catch (System.Exception e) // Don't let exceptions stop the other timers. { if (Debug.isDebugBuild) Debug.LogError(e.Message); } } } } } }