IUpdatable.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. // Animancer // https://kybernetik.com.au/animancer // Copyright 2018-2024 Kybernetik //
  2. using System;
  3. using System.Runtime.CompilerServices;
  4. using UnityEngine;
  5. using Object = UnityEngine.Object;
  6. namespace Animancer
  7. {
  8. /// <summary>[Pro-Only] An object that can be updated during Animancer's animation updates.</summary>
  9. ///
  10. /// <remarks>
  11. /// <strong>Example:</strong>
  12. /// Register to receive updates using <see cref="AnimancerGraph.RequirePreUpdate"/> or
  13. /// <see cref="AnimancerGraph.RequirePostUpdate"/> and stop
  14. /// receiving updates using <see cref="AnimancerGraph.CancelPreUpdate"/> or
  15. /// <see cref="AnimancerGraph.CancelPostUpdate"/>.
  16. /// <para></para><code>
  17. /// public sealed class MyUpdatable : IUpdatable
  18. /// {
  19. /// // Implement IUpdatable.
  20. /// // You can avoid this by inheriting from Updatable instead.
  21. /// int IUpdatable.UpdatableIndex { get; set; } = IUpdatable.List.NotInList;
  22. ///
  23. /// private AnimancerComponent _Animancer;
  24. ///
  25. /// public void StartUpdating(AnimancerComponent animancer)
  26. /// {
  27. /// _Animancer = animancer;
  28. ///
  29. /// // If you want Update to be called before the playables get updated.
  30. /// _Animancer.Graph.RequirePreUpdate(this);
  31. ///
  32. /// // If you want Update to be called after the playables get updated.
  33. /// _Animancer.Graph.RequirePostUpdate(this);
  34. /// }
  35. ///
  36. /// public void StopUpdating()
  37. /// {
  38. /// // If you used RequirePreUpdate.
  39. /// _Animancer.Graph.CancelPreUpdate(this);
  40. ///
  41. /// // If you used RequirePostUpdate.
  42. /// _Animancer.Graph.CancelPostUpdate(this);
  43. /// }
  44. ///
  45. /// void IUpdatable.Update()
  46. /// {
  47. /// // Called during every animation update.
  48. ///
  49. /// // AnimancerGraph.Current can be used to access the system it is being updated by.
  50. /// }
  51. /// }
  52. /// </code></remarks>
  53. ///
  54. /// https://kybernetik.com.au/animancer/api/Animancer/IUpdatable
  55. ///
  56. public interface IUpdatable
  57. {
  58. /************************************************************************************************************************/
  59. /// <summary>The index of this object in its <see cref="IndexedList{TItem, TIndexer}"/>.</summary>
  60. /// <remarks>Should be initialized to -1 to indicate that this object is not yet in a list.</remarks>
  61. int UpdatableIndex { get; set; }
  62. /// <summary>Updates this object.</summary>
  63. void Update();
  64. /************************************************************************************************************************/
  65. /// <summary>An <see cref="IIndexer{T}"/> for <see cref="IUpdatable"/>.</summary>
  66. public readonly struct Indexer : IIndexer<IUpdatable>
  67. {
  68. /************************************************************************************************************************/
  69. /// <inheritdoc/>
  70. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  71. public readonly int GetIndex(IUpdatable item)
  72. => item.UpdatableIndex;
  73. /// <inheritdoc/>
  74. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  75. public readonly void SetIndex(IUpdatable item, int index)
  76. => item.UpdatableIndex = index;
  77. /// <inheritdoc/>
  78. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  79. public readonly void ClearIndex(IUpdatable item)
  80. => item.UpdatableIndex = -1;
  81. /************************************************************************************************************************/
  82. }
  83. /************************************************************************************************************************/
  84. /// <summary>An <see cref="IndexedList{TItem, TAccessor}"/> of <see cref="IUpdatable"/>.</summary>
  85. public class List : IndexedList<IUpdatable, Indexer>
  86. {
  87. /************************************************************************************************************************/
  88. /// <summary>The default <see cref="IndexedList{TItem, TIndexer}.Capacity"/> for newly created lists.</summary>
  89. /// <remarks>Default value is 4.</remarks>
  90. public static new int DefaultCapacity { get; set; } = 4;
  91. /************************************************************************************************************************/
  92. /// <summary>Creates a new <see cref="List"/> with the <see cref="DefaultCapacity"/>.</summary>
  93. public List()
  94. : base(DefaultCapacity, new())
  95. { }
  96. /************************************************************************************************************************/
  97. /// <summary>Calls <see cref="Update"/> on all items in this list.</summary>
  98. /// <remarks>
  99. /// Uses <see cref="Debug.LogException(Exception, Object)"/> to handle exceptions and continues executing
  100. /// the remaining items if any occur.
  101. /// </remarks>
  102. public void UpdateAll()
  103. {
  104. BeginEnumeraton();
  105. ContinueEnumeration:
  106. try
  107. {
  108. while (TryEnumerateNext())
  109. {
  110. Current.Update();
  111. }
  112. }
  113. catch (Exception exception)
  114. {
  115. Debug.LogException(exception, AnimancerGraph.Current?.Component as Object);
  116. goto ContinueEnumeration;
  117. }
  118. }
  119. /************************************************************************************************************************/
  120. /// <summary>Clones any <see cref="ICloneable{T}"/> items.</summary>
  121. public void CloneFrom(
  122. List copyFrom,
  123. CloneContext context)
  124. {
  125. var count = copyFrom.Count;
  126. for (int i = 0; i < count; i++)
  127. if (copyFrom[i] is ICloneable<object> cloneable &&
  128. context.GetOrCreateClone(cloneable) is IUpdatable clone)
  129. Add(clone);
  130. }
  131. /************************************************************************************************************************/
  132. }
  133. /************************************************************************************************************************/
  134. }
  135. /// https://kybernetik.com.au/animancer/api/Animancer/AnimancerUtilities
  136. public static partial class AnimancerUtilities
  137. {
  138. /************************************************************************************************************************/
  139. /// <summary>Is the `updatable` currently in a list?</summary>
  140. public static bool IsInList(this IUpdatable updatable)
  141. => updatable.UpdatableIndex >= 0;
  142. /************************************************************************************************************************/
  143. }
  144. }