1- using System . Collections . Generic ;
1+ using BepInEx . Logging ;
2+ using System ;
3+ using System . Collections ;
4+ using System . Collections . Generic ;
25using System . Linq ;
36using UnityEngine ;
47using UnityEngine . SceneManagement ;
8+ using Logger = BepInEx . Logging . Logger ;
59
610namespace Silksong . UnityHelper . Extensions ;
711
@@ -10,6 +14,8 @@ namespace Silksong.UnityHelper.Extensions;
1014/// </summary>
1115public static class UnityExtensions
1216{
17+ private static readonly ManualLogSource Log = Logger . CreateLogSource ( $ "{ nameof ( UnityHelperPlugin ) } .{ nameof ( UnityExtensions ) } ") ;
18+
1319 /// <summary>
1420 /// Get the first component on a game object of a given type.
1521 ///
@@ -87,4 +93,65 @@ public static string GetNameInHierarchy(this Transform t)
8793
8894 return root . FindChild ( pathParts [ 1 ] ) ;
8995 }
96+
97+ /// <summary>
98+ /// Execute the given action after the specified number of seconds.
99+ /// </summary>
100+ /// <param name="component">The component used to start the coroutine. Often a plugin instance or <see cref="GameManager.instance"/>.</param>
101+ /// <param name="toInvoke">An Action to invoke.</param>
102+ /// <param name="seconds">The number of seconds to wait before invoking.</param>
103+ public static void InvokeAfterSeconds ( this MonoBehaviour component , Action toInvoke , float seconds )
104+ {
105+ component . StartCoroutine ( doInvoke ( ) ) ;
106+
107+ IEnumerator doInvoke ( )
108+ {
109+ yield return new WaitForSeconds ( seconds ) ;
110+
111+ try
112+ {
113+ toInvoke ( ) ;
114+ }
115+ catch ( Exception ex )
116+ {
117+ Log . LogError ( $ "Error invoking action { toInvoke . Method . Name } \n " + ex ) ;
118+ }
119+ }
120+ }
121+
122+ /// <summary>
123+ /// Execute the given action after the specified number of frames.
124+ /// </summary>
125+ /// <param name="component"><inheritdoc cref="InvokeAfterSeconds"/></param>
126+ /// <param name="toInvoke"><inheritdoc cref="InvokeAfterSeconds"/></param>
127+ /// <param name="numFrames">The number of frames to wait.</param>
128+ public static void InvokeAfterFrames ( this MonoBehaviour component , Action toInvoke , int numFrames )
129+ {
130+ component . StartCoroutine ( doInvoke ( ) ) ;
131+
132+ IEnumerator doInvoke ( )
133+ {
134+ for ( int i = 0 ; i < numFrames ; i ++ )
135+ {
136+ yield return null ;
137+ }
138+
139+ try
140+ {
141+ toInvoke ( ) ;
142+ }
143+ catch ( Exception ex )
144+ {
145+ Log . LogError ( $ "Error invoking action { toInvoke . Method . Name } \n " + ex ) ;
146+ }
147+ }
148+ }
149+
150+ /// <summary>
151+ /// Execute the given action after 1 frame has passed.
152+ /// </summary>
153+ /// <param name="component"><inheritdoc cref="InvokeAfterSeconds"/></param>
154+ /// <param name="toInvoke"><inheritdoc cref="InvokeAfterSeconds"/></param>
155+ public static void InvokeNextFrame ( this MonoBehaviour component , Action toInvoke ) => component . InvokeAfterFrames ( toInvoke , 1 ) ;
156+
90157}
0 commit comments