Skip to content

Commit

Permalink
Add AccessTools.AsyncMoveNext and the Async MethodType
Browse files Browse the repository at this point in the history
  • Loading branch information
Windows10CE committed Jul 2, 2023
1 parent e46a536 commit f618ca7
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 2 deletions.
5 changes: 5 additions & 0 deletions Harmony/Internal/PatchTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ internal static MethodBase GetOriginalMethod(this HarmonyMethod attr)
return null;
return AccessTools.EnumeratorMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(),
attr.methodName, attr.argumentTypes));

case MethodType.Async:
if (attr.methodName is null)
return null;
return AccessTools.AsyncMoveNext(AccessTools.DeclaredMethod(attr.GetDeclaringType(), attr.methodName, attr.argumentTypes));
}
}
catch (AmbiguousMatchException ex)
Expand Down
3 changes: 2 additions & 1 deletion Harmony/Public/Attributes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ public enum MethodType
StaticConstructor,
/// <summary>This is an enumerator (<see cref="IEnumerable{T}"/>, <see cref="IEnumerator{T}"/> or UniTask coroutine)</summary>
/// <remarks>This path will target the <see cref="IEnumerator.MoveNext"/> method that contains the actual enumerator code</remarks>
Enumerator
Enumerator,
Async
}

/// <summary>Specifies the type of argument</summary>
Expand Down
2 changes: 1 addition & 1 deletion Harmony/Public/Harmony.cs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ public void PatchAll(Assembly assembly)
{
AccessTools.GetTypesFromAssembly(assembly).Do(type => CreateClassProcessor(type).Patch());
}

/// <summary>Searches the given type for Harmony annotation and uses them to create patches</summary>
/// <param name="type">The type to search</param>
///
Expand Down
32 changes: 32 additions & 0 deletions Harmony/Tools/AccessTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,38 @@ public static MethodInfo EnumeratorMoveNext(MethodBase enumerator)
return moveNext;
}

private static readonly Type _stateMachineAttributeType = typeof(object).Assembly.GetType("System.Runtime.CompilerServices.AsyncStateMachineAttribute");
private static readonly MethodInfo _stateMachineTypeGetter = _stateMachineAttributeType?.GetProperty("StateMachineType").GetGetMethod();

/// <summary>Gets the <see cref="IAsyncStateMachine.MoveNext" /> method of an async method's state machine</summary>
/// <param name="method">Async method that creates the state machine internally</param>
/// <returns>The internal <see cref="IAsyncStateMachine.MoveNext" /> method of the async state machine or <b>null</b> if no valid async method is detected</returns>
public static MethodInfo AsyncMoveNext(MethodBase method)
{
if (method is null)
{
FileLog.Debug("AccessTools.AsyncMoveNext: method is null");
return null;
}

var asyncAttribute = method.GetCustomAttributes(false).FirstOrDefault(a => a.GetType() == _stateMachineAttributeType);
if (asyncAttribute == null)
{
FileLog.Debug($"AccessTools.AsyncMoveNext: Could not find AsyncStateMachine for {method.FullDescription()}");
return null;
}

var asyncStateMachineType = (Type)_stateMachineTypeGetter.Invoke(method, null);
var asyncMethodBody = DeclaredMethod(asyncStateMachineType, "MoveNext");
if (asyncMethodBody == null)
{
FileLog.Debug($"AccessTools.AsyncMoveNext: Could not find async method body for {method.FullDescription()}");
return null;
}

return asyncMethodBody;
}

/// <summary>Gets the names of all method that are declared in a type</summary>
/// <param name="type">The declaring class/type</param>
/// <returns>A list of method names</returns>
Expand Down

0 comments on commit f618ca7

Please sign in to comment.