Skip to content

Commit

Permalink
Implement async OnEnable/OnDisable
Browse files Browse the repository at this point in the history
  • Loading branch information
Meivyn committed Jan 9, 2024
1 parent fc03ad9 commit 4148b27
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 18 deletions.
15 changes: 11 additions & 4 deletions IPA.Loader/Loader/Composite/CompositeBSPlugin.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine.SceneManagement;
using Logger = IPA.Logging.Logger;

Expand All @@ -10,9 +12,9 @@ internal class CompositeBSPlugin
{
private readonly IEnumerable<PluginExecutor> plugins;

private delegate void CompositeCall(PluginExecutor plugin);
public CompositeBSPlugin(IEnumerable<PluginExecutor> plugins)
private delegate Task CompositeCall(PluginExecutor plugin);

public CompositeBSPlugin(IEnumerable<PluginExecutor> plugins)
{
this.plugins = plugins;
}
Expand All @@ -23,7 +25,12 @@ private void Invoke(CompositeCall callback, [CallerMemberName] string method = "
try
{
if (plugin != null)
callback(plugin);
{
callback(plugin).ContinueWith(t =>
{
Logger.Default.Error($"{plugin.Metadata.Name} {method}: {t.Exception!.InnerException}");
}, CancellationToken.None, TaskContinuationOptions.OnlyOnFaulted, TaskScheduler.Default);
}
}
catch (Exception ex)
{
Expand Down
50 changes: 36 additions & 14 deletions IPA.Loader/Loader/PluginExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public PluginExecutor(PluginMetadata meta, Special specialType = Special.None)
if (specialType != Special.None)
{
CreatePlugin = m => null;
LifecycleEnable = o => { };
LifecycleEnable = o => TaskEx.WhenAll();
LifecycleDisable = o => TaskEx.WhenAll();
}
else
Expand All @@ -48,8 +48,7 @@ public PluginExecutor(PluginMetadata meta, Special specialType = Special.None)

public object Instance { get; private set; } = null;
private Func<PluginMetadata, object> CreatePlugin { get; set; }
private Action<object> LifecycleEnable { get; set; }
// disable may be async (#24)
private Func<object, Task> LifecycleEnable { get; set; }
private Func<object, Task> LifecycleDisable { get; set; }

public void Create()
Expand All @@ -58,7 +57,7 @@ public void Create()
Instance = CreatePlugin(Metadata);
}

public void Enable() => LifecycleEnable(Instance);
public Task Enable() => LifecycleEnable(Instance);
public Task Disable() => LifecycleDisable(Instance);


Expand Down Expand Up @@ -120,7 +119,7 @@ private static Func<PluginMetadata, object> MakeCreateFunc(Type type, string nam
return createExpr.Compile();
}
// TODO: make enable and disable able to take a bool indicating which it is
private static Action<object> MakeLifecycleEnableFunc(Type type, string name)
private static Func<object, Task> MakeLifecycleEnableFunc(Type type, string name)
{
var noEnableDisable = type.GetCustomAttribute<NoEnableDisableAttribute>() is not null;
var enableMethods = type.GetMethods(BindingFlags.Public | BindingFlags.Instance)
Expand All @@ -132,24 +131,47 @@ private static Action<object> MakeLifecycleEnableFunc(Type type, string name)
{
if (!noEnableDisable)
Logger.Loader.Notice($"Plugin {name} has no methods marked [OnStart] or [OnEnable]. Is this intentional?");
return o => { };
return o => TaskEx.WhenAll();
}

var taskMethods = new List<MethodInfo>();
var nonTaskMethods = new List<MethodInfo>();
foreach (var m in enableMethods)
{
if (m.GetParameters().Length > 0)
throw new InvalidOperationException($"Method {m} on {type.FullName} is marked [OnStart] or [OnEnable] and has parameters.");
if (m.ReturnType != typeof(void))
Logger.Loader.Warn($"Method {m} on {type.FullName} is marked [OnStart] or [OnEnable] and returns a value. It will be ignored.");
{
if (typeof(Task).IsAssignableFrom(m.ReturnType))
{
taskMethods.Add(m);
continue;
}

Logger.Loader.Warn($"Method {m} on {type.FullName} is marked [OnStart] or [OnEnable] and returns a non-Task value. It will be ignored.");
}

nonTaskMethods.Add(m);
}

Expression<Func<Task>> completedTaskDel = () => TaskEx.WhenAll();
var getCompletedTask = completedTaskDel.Body;
var taskWhenAll = typeof(TaskEx).GetMethod(nameof(TaskEx.WhenAll), new[] { typeof(Task[]) });

var objParam = Expression.Parameter(typeof(object), "obj");
var instVar = ExpressionEx.Variable(type, "inst");
var createExpr = Expression.Lambda<Action<object>>(
var createExpr = Expression.Lambda<Func<object, Task>>(
ExpressionEx.Block(new[] { instVar },
enableMethods
nonTaskMethods
.Select(m => (Expression)Expression.Call(instVar, m))
.Prepend(ExpressionEx.Assign(instVar, Expression.Convert(objParam, type)))),
.Prepend(ExpressionEx.Assign(instVar, Expression.Convert(objParam, type)))
.Append(
taskMethods.Count == 0
? getCompletedTask
: Expression.Call(taskWhenAll,
Expression.NewArrayInit(typeof(Task),
taskMethods.Select(m =>
(Expression)Expression.Convert(Expression.Call(instVar, m), typeof(Task))))))),
objParam);
return createExpr.Compile();
}
Expand Down Expand Up @@ -181,8 +203,8 @@ private static Func<object, Task> MakeLifecycleDisableFunc(Type type, string nam
taskMethods.Add(m);
continue;
}
else
Logger.Loader.Warn($"Method {m} on {type.FullName} is marked [OnExit] or [OnDisable] and returns a non-Task value. It will be ignored.");

Logger.Loader.Warn($"Method {m} on {type.FullName} is marked [OnExit] or [OnDisable] and returns a non-Task value. It will be ignored.");
}

nonTaskMethods.Add(m);
Expand All @@ -200,11 +222,11 @@ private static Func<object, Task> MakeLifecycleDisableFunc(Type type, string nam
.Select(m => (Expression)Expression.Call(instVar, m))
.Prepend(ExpressionEx.Assign(instVar, Expression.Convert(objParam, type)))
.Append(
taskMethods.Count == 0
taskMethods.Count == 0
? getCompletedTask
: Expression.Call(taskWhenAll,
Expression.NewArrayInit(typeof(Task),
taskMethods.Select(m =>
taskMethods.Select(m =>
(Expression)Expression.Convert(Expression.Call(instVar, m), typeof(Task))))))),
objParam);
return createExpr.Compile();
Expand Down

0 comments on commit 4148b27

Please sign in to comment.