暫無描述
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.

ActionScheduler.cs 5.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. using System;
  2. using System.Collections.Generic;
  3. using UnityEngine.LowLevel;
  4. using Unity.Services.Core.Internal;
  5. using NotNull = JetBrains.Annotations.NotNullAttribute;
  6. namespace Unity.Services.Core.Scheduler.Internal
  7. {
  8. class ActionScheduler : IActionScheduler
  9. {
  10. const long k_MinimumIdValue = 1;
  11. internal readonly PlayerLoopSystem SchedulerLoopSystem;
  12. readonly ITimeProvider m_TimeProvider;
  13. /// <remarks>
  14. /// Members requiring thread safety:
  15. /// * <see cref="m_NextId"/>.
  16. /// * <see cref="m_ScheduledActions"/>.
  17. /// * <see cref="m_IdScheduledInvocationMap"/>.
  18. /// </remarks>
  19. readonly object m_Lock = new object();
  20. readonly MinimumBinaryHeap<ScheduledInvocation> m_ScheduledActions
  21. = new MinimumBinaryHeap<ScheduledInvocation>(new ScheduledInvocationComparer());
  22. readonly Dictionary<long, ScheduledInvocation> m_IdScheduledInvocationMap
  23. = new Dictionary<long, ScheduledInvocation>();
  24. readonly List<ScheduledInvocation> m_ExpiredActions = new List<ScheduledInvocation>();
  25. long m_NextId = k_MinimumIdValue;
  26. public ActionScheduler()
  27. : this(new UtcTimeProvider()) {}
  28. public ActionScheduler(ITimeProvider timeProvider)
  29. {
  30. m_TimeProvider = timeProvider;
  31. SchedulerLoopSystem = new PlayerLoopSystem
  32. {
  33. type = typeof(ActionScheduler),
  34. updateDelegate = ExecuteExpiredActions
  35. };
  36. }
  37. public int ScheduledActionsCount => m_ScheduledActions.Count;
  38. public long ScheduleAction([NotNull] Action action, double delaySeconds = 0)
  39. {
  40. if (delaySeconds < 0)
  41. {
  42. throw new ArgumentException("delaySeconds can not be negative");
  43. }
  44. if (action is null)
  45. {
  46. throw new ArgumentNullException(nameof(action));
  47. }
  48. lock (m_Lock)
  49. {
  50. var scheduledInvocation = new ScheduledInvocation
  51. {
  52. Action = action,
  53. InvocationTime = m_TimeProvider.Now.AddSeconds(delaySeconds),
  54. ActionId = m_NextId++
  55. };
  56. if (m_NextId < k_MinimumIdValue)
  57. {
  58. m_NextId = k_MinimumIdValue;
  59. }
  60. m_ScheduledActions.Insert(scheduledInvocation);
  61. m_IdScheduledInvocationMap.Add(scheduledInvocation.ActionId, scheduledInvocation);
  62. return scheduledInvocation.ActionId;
  63. }
  64. }
  65. public void CancelAction(long actionId)
  66. {
  67. lock (m_Lock)
  68. {
  69. if (!m_IdScheduledInvocationMap.TryGetValue(actionId, out var scheduledInvocation))
  70. {
  71. return;
  72. }
  73. m_ScheduledActions.Remove(scheduledInvocation);
  74. m_IdScheduledInvocationMap.Remove(scheduledInvocation.ActionId);
  75. }
  76. }
  77. internal void ExecuteExpiredActions()
  78. {
  79. lock (m_Lock)
  80. {
  81. m_ExpiredActions.Clear();
  82. while (m_ScheduledActions.Count > 0
  83. && m_ScheduledActions.Min?.InvocationTime <= m_TimeProvider.Now)
  84. {
  85. var expiredAction = m_ScheduledActions.ExtractMin();
  86. m_ExpiredActions.Add(expiredAction);
  87. m_ScheduledActions.Remove(expiredAction);
  88. m_IdScheduledInvocationMap.Remove(expiredAction.ActionId);
  89. }
  90. foreach (var expiredAction in m_ExpiredActions)
  91. {
  92. try
  93. {
  94. expiredAction.Action();
  95. }
  96. catch (Exception e)
  97. {
  98. CoreLogger.LogException(e);
  99. }
  100. }
  101. }
  102. }
  103. internal static void UpdateCurrentPlayerLoopWith(
  104. List<PlayerLoopSystem> subSystemList, PlayerLoopSystem currentPlayerLoop)
  105. {
  106. currentPlayerLoop.subSystemList = subSystemList.ToArray();
  107. PlayerLoop.SetPlayerLoop(currentPlayerLoop);
  108. }
  109. public void JoinPlayerLoopSystem()
  110. {
  111. var currentPlayerLoop = PlayerLoop.GetCurrentPlayerLoop();
  112. var currentSubSystems = new List<PlayerLoopSystem>(currentPlayerLoop.subSystemList);
  113. if (!currentSubSystems.Contains(SchedulerLoopSystem))
  114. {
  115. currentSubSystems.Add(SchedulerLoopSystem);
  116. UpdateCurrentPlayerLoopWith(currentSubSystems, currentPlayerLoop);
  117. }
  118. }
  119. public void QuitPlayerLoopSystem()
  120. {
  121. var currentPlayerLoop = PlayerLoop.GetCurrentPlayerLoop();
  122. var currentSubSystems = new List<PlayerLoopSystem>(currentPlayerLoop.subSystemList);
  123. if (currentSubSystems.Remove(SchedulerLoopSystem))
  124. {
  125. UpdateCurrentPlayerLoopWith(currentSubSystems, currentPlayerLoop);
  126. }
  127. }
  128. }
  129. }