搬运自OpenMod官网,经过翻译,可能有些不足,欢迎指正!原文链接
任务调度
OpenMod提供AsyncHelper.Schedule方法为了fire-and-forget任务。
它将给定的任务排队到线程池中。这可用于延迟或定期运行任务。
通用
以下示例适用于所有OpenMod平台。
运行延迟的任务
您可以这样延迟任务:
public async Task MyTask(){ m_Logger.LogInformation("等待5秒..."); await Task.Delay(TimeSpan.FromSeconds(5)); m_Logger.LogInformation("完成!"); }
那就像这样命名AsyncHelper.Schedule:
AsyncHelper.Schedule("My Task", () => MyTask());
定期运行任务
如果要定期运行任务,只需在任务周围环绕一个while循环:
public async Task MyPeriodicTask(IOpenModPlugin myPlugin) { while(myPlugin.IsComponentAlive) // 确保此任务仅在加载插件时运行 { m_Logger.LogInformation("等待5秒..."); await Task.Delay(TimeSpan.FromSeconds(5)); m_Logger.LogInformation("完成!"); } }
像前面一样命名AsyncHelper.Schedule,但要传递插件实例:
AsyncHelper.Schedule("My Task", () => MyPeriodicTask(myPlugin));
在插件卸载后不要让任务继续运行。确保在插件卸载时任务停止运行。您可以使用您的插件IsComponentAlive属性或取消令牌来执行此操作。
不要使用Thread.Sleep或者类似的阻塞方法,比如任务中的non-async I/O方法。这些方法将阻塞工作线程并阻止其他任务运行。始终使用异步替代方法,例如Task.Delay代替Thread.Sleep或者Stream.ReadAsync文件代替Stream.Read。
Unity引擎
以下示例仅适用于使用UnityEngine的游戏,如Unturned。
在每次更新时运行任务
与定期运行任务的示例一样,我们将再次使用while循环。
注意返回类型如何更改为UniTask,以及对AsyncHelper.Schedule方法的调用是如何更改的。
public async UniTask MyUpdateTask(IOpenModPlugin myPlugin){ await UniTask.SwitchToMainThread(); // 确保先在主线程上运行。 int i = 0; while(myPlugin.IsComponentAlive) // 确保此任务仅在加载插件时运行 { await UniTask.DelayFrame(1, PlayerLoopTiming.Update); m_Logger.LogInformation($"Frame update: {++i}"); } }
让我们把它分解一下。
检查以下线路:await UniTask.DelayFrame(1, PlayerLoopTiming.Update)
第一个参数‘1’定义要等待多少帧。因此,这个示例将始终等待一帧,因此在每次帧更新时都会运行。
第二个参数‘PlayerLoopTiming.Update’设置它应等待的更新类型。在本例中,这是一个普通的帧更新。您也可以使用其他更新类型,例如FixedUpdate。
以下更新类型可用:
EarlyUpdate
LastEarlyUpdate
FixedUpdate
LastFixedUpdate
PreUpdate
LastPreUpdate
Update
LastUpdate
PreLateUpdate
LastPreLateUpdate
PostLateUpdate
LastPostLateUpdate
要计划任务,请按以下方式调用AsyncHelper:
AsyncHelper.Schedule("My Task", () => MyUpdateTask(myPlugin).AsTask() /* 对于UniTask,您必须使用,AsTask() */);