AR Design
UBC EML collab with UBC SALA - visualizing IoT data in AR
TimerScheduler.cs
Go to the documentation of this file.
1 // Copyright (c) Microsoft Corporation. All rights reserved.
2 // Licensed under the MIT License. See LICENSE in the project root for license information.
3 
4 using System.Collections.Generic;
5 using UnityEngine;
6 
7 namespace HoloToolkit.Unity
8 {
33  public sealed class TimerScheduler : Singleton<TimerScheduler>
34  {
35  private struct TimerData
36  {
37  public Callback Callback;
38  public float Duration;
39  public bool Loop;
40  public int Id;
41 
42  public TimerData(float time, Callback callback, bool loop, int id)
43  {
44  Callback = callback;
45  Loop = loop;
46  Duration = time;
47  Id = id;
48  }
49  }
50 
51  private struct TimerIdPair
52  {
53  public int Id;
54  public int KeyTime;
55  }
56 
57  public delegate void Callback();
58 
59  private PriorityQueue<int, TimerData> timers;
60  private List<TimerData> deferredTimers;
61  private List<TimerIdPair> activeTimers;
62  private int nextTimerId;
63 
64  protected override void Awake()
65  {
66  base.Awake();
67 
68  timers = new PriorityQueue<int, TimerData>();
69  deferredTimers = new List<TimerData>(10);
70  activeTimers = new List<TimerIdPair>(20);
71 
72  nextTimerId = 1; // 0 is reserved
73  }
74 
75  private int GetKeyTime(float time)
76  {
77  // key time is nearest millisecond
78  return (int)(time * 1000);
79  }
80 
81  private bool HasKeyTimePassed(int key)
82  {
83  return key <= GetKeyTime(Time.time);
84  }
85 
86  private int AddTimer(TimerData timer, bool deferred = false)
87  {
88  if (deferred)
89  {
90  deferredTimers.Add(timer);
91  }
92  else
93  {
94  // calculate the key time for the evaluation point. Multiple timers can have this value.
95  int keyTime = GetKeyTime(Time.time + timer.Duration);
96 
97  // re-add timer to queue
98  timers.Push(keyTime, timer);
99 
100  // add to list of active timers
101  activeTimers.Add(new TimerIdPair { Id = timer.Id, KeyTime = keyTime });
102  }
103 
104  // make sure the scheduler is enabled now that we have a new timer.
105  enabled = true;
106 
107  return timer.Id;
108  }
109 
110  private int GetActiveTimerIndex(int timerId)
111  {
112  for (int i = 0; i < activeTimers.Count; ++i)
113  {
114  if (activeTimers[i].Id == timerId)
115  {
116  return i;
117  }
118  }
119 
120  return -1;
121  }
122 
123  private bool RemoveActiveTimer(int timerId)
124  {
125  int index = GetActiveTimerIndex(timerId);
126  if (index > -1)
127  {
128  activeTimers.RemoveAt(index);
129  return true;
130  }
131 
132  return false;
133  }
134 
135  private int GetTimerDeferredIndex(int timerId)
136  {
137  for (int i = 0; i < deferredTimers.Count; ++i)
138  {
139  if (deferredTimers[i].Id == timerId)
140  {
141  return i;
142  }
143  }
144 
145  return -1;
146  }
147 
148  private void AddDeferredTimers()
149  {
150  for (int i = 0; i < deferredTimers.Count; i++)
151  {
152  AddTimer(deferredTimers[i]);
153  }
154 
155  deferredTimers.Clear();
156  }
157 
158  private void Update()
159  {
160  // while waiting for an event to happen, we'll just early out
161  while (timers.Count > 0 && HasKeyTimePassed(timers.Top.Key))
162  {
163  TimerData timer = timers.Top.Value;
164 
165  // remove from active timers
166  RemoveActiveTimer(timer.Id);
167 
168  // remove from queue
169  timers.Pop();
170 
171  // loop events by just reinserting them
172  if (timer.Loop)
173  {
174  // re-add timer
175  AddTimer(timer);
176  }
177 
178  // activate the callback. call this after loop reinsertion, because
179  // the callback could call StopTimer.
180  timer.Callback();
181  }
182 
183  AddDeferredTimers();
184 
185  // if there are no active timers there is no need to update every frame.
186  if (timers.Count == 0)
187  {
188  enabled = false;
189  }
190  }
191 
199  public Timer StartTimer(float timeSeconds, Callback callback, bool loop = false, bool deferred = false)
200  {
201  int id = AddTimer(new TimerData(timeSeconds, callback, loop, nextTimerId++), deferred);
202 
203  // create a new id, and make a new timer with it
204  return new Timer(id);
205  }
206 
212  public void StopTimer(Timer timerId)
213  {
214  if (timerId.Id != Timer.Invalid.Id)
215  {
216  int index = GetActiveTimerIndex(timerId.Id);
217  if (index > -1)
218  {
219  int priority = activeTimers[index].KeyTime;
220  activeTimers.RemoveAt(index);
221 
222  // TODO: remove specific value
223  // allocation here is fine, since it's a temporary, and will get cleaned in gen 0 GC
224  int id = timerId.Id;
225  timers.RemoveAtPriority(priority, t => t.Id == id);
226  }
227  else
228  {
229  int deferredIndex = GetTimerDeferredIndex(timerId.Id);
230  if (deferredIndex > -1)
231  {
232  deferredTimers.RemoveAt(deferredIndex);
233  }
234  }
235  }
236  }
237 
238  public bool IsTimerActive(Timer timerId)
239  {
240  return GetActiveTimerIndex(timerId.Id) > -1 || GetTimerDeferredIndex(timerId.Id) > -1;
241  }
242  }
243 }
Timer StartTimer(float timeSeconds, Callback callback, bool loop=false, bool deferred=false)
Creates a new timer event which will be added next frame.
A scheduler that manages various timers.
Structure that defines a timer. A timer can be scheduled through the TimerScheduler.
Definition: Timer.cs:9
static Timer Invalid
Definition: Timer.cs:13
int Count
Number of elements in priority queue
void StopTimer(Timer timerId)
Disable an active timer.
KeyValuePair< TPriority, TValue > Top
Get the element with the minimum priority in the queue. The Key in the return value is the priority...
bool RemoveAtPriority(TPriority priority, Predicate< TValue > shouldRemove)
Removes all elements with this priority from the queue.
override void Awake()
Base Awake method that sets the Singleton&#39;s unique instance. Called by Unity when initializing a Mono...
void Push(TPriority priority, TValue value)
Add an element to the priority queue.
bool IsTimerActive(Timer timerId)
KeyValuePair< TPriority, TValue > Pop()
Pop the minimal element of the queue. Will fail at runtime if queue is empty.
Singleton behaviour class, used for components that should only have one instance.
Definition: Singleton.cs:14