using System; using System.Collections.Generic; using System.Threading.Tasks; using GameFramework; using GameFramework.DataTable; using GameFramework.Event; using GameFramework.Resource; using UnityEngine; using UnityGameFramework.Runtime; namespace UGFExtensions.Await { public static partial class AwaitableExtensions { private static readonly Dictionary> s_UIFormTcs = new Dictionary>(); private static readonly Dictionary> s_EntityTcs = new Dictionary>(); private static readonly Dictionary> s_DataTableTcs = new Dictionary>(); private static readonly Dictionary> s_LoadSceneTcs = new Dictionary>(); private static readonly Dictionary> s_UnLoadSceneTcs = new Dictionary>(); private static readonly HashSet s_WebSerialIDs = new HashSet(); private static readonly List s_DelayReleaseWebResult = new List(); private static readonly HashSet s_DownloadSerialIds = new HashSet(); private static readonly List s_DelayReleaseDownloadResult = new List(); #if UNITY_EDITOR private static bool s_IsSubscribeEvent = false; #endif /// /// 注册需要的事件 (需再流程入口处调用 防止框架重启导致事件被取消问题) /// public static void SubscribeEvent() { EventComponent eventComponent = UnityGameFramework.Runtime.GameEntry.GetComponent(); eventComponent.Subscribe(OpenUIFormSuccessEventArgs.EventId, OnOpenUIFormSuccess); eventComponent.Subscribe(OpenUIFormFailureEventArgs.EventId, OnOpenUIFormFailure); eventComponent.Subscribe(ShowEntitySuccessEventArgs.EventId, OnShowEntitySuccess); eventComponent.Subscribe(ShowEntityFailureEventArgs.EventId, OnShowEntityFailure); eventComponent.Subscribe(LoadSceneSuccessEventArgs.EventId, OnLoadSceneSuccess); eventComponent.Subscribe(LoadSceneFailureEventArgs.EventId, OnLoadSceneFailure); eventComponent.Subscribe(UnloadSceneSuccessEventArgs.EventId, OnUnloadSceneSuccess); eventComponent.Subscribe(UnloadSceneFailureEventArgs.EventId, OnUnloadSceneFailure); // eventComponent.Subscribe(LoadDataTableSuccessEventArgs.EventId, OnLoadDataTableSuccess); // eventComponent.Subscribe(LoadDataTableFailureEventArgs.EventId, OnLoadDataTableFailure); eventComponent.Subscribe(WebRequestSuccessEventArgs.EventId, OnWebRequestSuccess); eventComponent.Subscribe(WebRequestFailureEventArgs.EventId, OnWebRequestFailure); eventComponent.Subscribe(DownloadSuccessEventArgs.EventId, OnDownloadSuccess); eventComponent.Subscribe(DownloadFailureEventArgs.EventId, OnDownloadFailure); #if UNITY_EDITOR s_IsSubscribeEvent = true; #endif } #if UNITY_EDITOR private static void TipsSubscribeEvent() { if (!s_IsSubscribeEvent) { throw new Exception("Use await/async extensions must to subscribe event!"); } } #endif /// /// 打开界面(可等待) /// public static Task OpenUIFormAsync(this UIComponent uiComponent,string uiFormAssetName, string uiGroupName, int priority, bool pauseCoveredUIForm, object userData) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif int serialId = uiComponent.OpenUIForm(uiFormAssetName, uiGroupName, priority, pauseCoveredUIForm, userData); var tcs = new TaskCompletionSource(); s_UIFormTcs.Add(serialId, tcs); return tcs.Task; } private static void OnOpenUIFormSuccess(object sender, GameEventArgs e) { OpenUIFormSuccessEventArgs ne = (OpenUIFormSuccessEventArgs)e; s_UIFormTcs.TryGetValue(ne.UIForm.SerialId, out TaskCompletionSource tcs); if (tcs != null) { tcs.SetResult(ne.UIForm); s_UIFormTcs.Remove(ne.UIForm.SerialId); } } private static void OnOpenUIFormFailure(object sender, GameEventArgs e) { OpenUIFormFailureEventArgs ne = (OpenUIFormFailureEventArgs)e; s_UIFormTcs.TryGetValue(ne.SerialId, out TaskCompletionSource tcs); if (tcs != null) { Debug.LogError(ne.ErrorMessage); tcs.SetException(new GameFrameworkException(ne.ErrorMessage)); s_UIFormTcs.Remove(ne.SerialId); } } /// /// 显示实体(可等待) /// public static Task ShowEntityAsync(this EntityComponent entityComponent, int entityId, Type entityLogicType, string entityAssetName, string entityGroupName, int priority,object userData) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tcs = new TaskCompletionSource(); s_EntityTcs.Add(entityId, tcs); entityComponent.ShowEntity(entityId, entityLogicType, entityAssetName, entityGroupName, priority, userData); return tcs.Task; } private static void OnShowEntitySuccess(object sender, GameEventArgs e) { ShowEntitySuccessEventArgs ne = (ShowEntitySuccessEventArgs)e; s_EntityTcs.TryGetValue(ne.Entity.Id, out var tcs); if (tcs != null) { tcs.SetResult(ne.Entity); s_EntityTcs.Remove(ne.Entity.Id); } } private static void OnShowEntityFailure(object sender, GameEventArgs e) { ShowEntityFailureEventArgs ne = (ShowEntityFailureEventArgs)e; s_EntityTcs.TryGetValue(ne.EntityId, out var tcs); if (tcs != null) { Debug.LogError(ne.ErrorMessage); tcs.SetException(new GameFrameworkException(ne.ErrorMessage)); s_EntityTcs.Remove(ne.EntityId); } } /// /// 加载场景(可等待) /// public static async Task LoadSceneAsync(this SceneComponent sceneComponent, string sceneAssetName) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tcs = new TaskCompletionSource(); var isUnLoadScene = s_UnLoadSceneTcs.TryGetValue(sceneAssetName, out var unloadSceneTcs); if (isUnLoadScene) { await unloadSceneTcs.Task; } s_LoadSceneTcs.Add(sceneAssetName, tcs); try { sceneComponent.LoadScene(sceneAssetName); } catch (Exception e) { Debug.LogError(e.ToString()); tcs.SetException(e); s_LoadSceneTcs.Remove(sceneAssetName); } return await tcs.Task; } private static void OnLoadSceneSuccess(object sender, GameEventArgs e) { LoadSceneSuccessEventArgs ne = (LoadSceneSuccessEventArgs)e; s_LoadSceneTcs.TryGetValue(ne.SceneAssetName, out var tcs); if (tcs != null) { tcs.SetResult(true); s_LoadSceneTcs.Remove(ne.SceneAssetName); } } private static void OnLoadSceneFailure(object sender, GameEventArgs e) { LoadSceneFailureEventArgs ne = (LoadSceneFailureEventArgs)e; s_LoadSceneTcs.TryGetValue(ne.SceneAssetName, out var tcs); if (tcs != null) { Debug.LogError(ne.ErrorMessage); tcs.SetException(new GameFrameworkException(ne.ErrorMessage)); s_LoadSceneTcs.Remove(ne.SceneAssetName); } } /// /// 卸载场景(可等待) /// public static async Task UnLoadSceneAsync(this SceneComponent sceneComponent, string sceneAssetName) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tcs = new TaskCompletionSource(); var isLoadSceneTcs = s_LoadSceneTcs.TryGetValue(sceneAssetName, out var loadSceneTcs); if (isLoadSceneTcs) { Debug.Log("Unload loading scene"); await loadSceneTcs.Task; } s_UnLoadSceneTcs.Add(sceneAssetName, tcs); try { sceneComponent.UnloadScene(sceneAssetName); } catch (Exception e) { Debug.LogError(e.ToString()); tcs.SetException(e); s_UnLoadSceneTcs.Remove(sceneAssetName); } return await tcs.Task; } private static void OnUnloadSceneSuccess(object sender, GameEventArgs e) { UnloadSceneSuccessEventArgs ne = (UnloadSceneSuccessEventArgs)e; s_UnLoadSceneTcs.TryGetValue(ne.SceneAssetName, out var tcs); if (tcs != null) { tcs.SetResult(true); s_UnLoadSceneTcs.Remove(ne.SceneAssetName); } } private static void OnUnloadSceneFailure(object sender, GameEventArgs e) { UnloadSceneFailureEventArgs ne = (UnloadSceneFailureEventArgs)e; s_UnLoadSceneTcs.TryGetValue(ne.SceneAssetName, out var tcs); if (tcs != null) { Debug.LogError($"Unload scene {ne.SceneAssetName} failure."); tcs.SetException(new GameFrameworkException($"Unload scene {ne.SceneAssetName} failure.")); s_UnLoadSceneTcs.Remove(ne.SceneAssetName); } } /// /// 加载资源(可等待) /// public static Task LoadAssetAsync(this ResourceComponent resourceComponent, string assetName) where T : UnityEngine.Object { #if UNITY_EDITOR TipsSubscribeEvent(); #endif TaskCompletionSource loadAssetTcs = new TaskCompletionSource(); resourceComponent.LoadAsset(assetName, typeof(T), new LoadAssetCallbacks( (tempAssetName, asset, duration, userdata) => { var source = loadAssetTcs; loadAssetTcs = null; T tAsset = asset as T; if (tAsset != null) { source.SetResult(tAsset); } else { Debug.LogError($"Load asset failure load type is {asset.GetType()} but asset type is {typeof(T)}."); source.SetException(new GameFrameworkException( $"Load asset failure load type is {asset.GetType()} but asset type is {typeof(T)}.")); } }, (tempAssetName, status, errorMessage, userdata) => { Debug.LogError(errorMessage); loadAssetTcs.SetException(new GameFrameworkException(errorMessage)); } )); return loadAssetTcs.Task; } /// /// 加载多个资源(可等待) /// public static async Task LoadAssetsAsync(this ResourceComponent resourceComponent, string[] assetName) where T : UnityEngine.Object { #if UNITY_EDITOR TipsSubscribeEvent(); #endif if (assetName == null) { return null; } T[] assets = new T[assetName.Length]; Task[] tasks = new Task[assets.Length]; for (int i = 0; i < tasks.Length; i++) { tasks[i] = resourceComponent.LoadAssetAsync(assetName[i]); } await Task.WhenAll(tasks); for (int i = 0; i < assets.Length; i++) { assets[i] = tasks[i].Result; } return assets; } /// /// 增加Web请求任务(可等待) /// public static Task AddWebRequestAsync(this WebRequestComponent webRequestComponent, string webRequestUri, WWWForm wwwForm = null, object userdata = null) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tsc = new TaskCompletionSource(); int serialId = webRequestComponent.AddWebRequest(webRequestUri, wwwForm, AwaitDataWrap.Create(userdata, tsc)); s_WebSerialIDs.Add(serialId); return tsc.Task; } /// /// 增加Web请求任务(可等待) /// public static Task AddWebRequestAsync(this WebRequestComponent webRequestComponent, string webRequestUri, byte[] postData, object userdata = null) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tsc = new TaskCompletionSource(); int serialId = webRequestComponent.AddWebRequest(webRequestUri, postData, AwaitDataWrap.Create(userdata, tsc)); s_WebSerialIDs.Add(serialId); return tsc.Task; } private static void OnWebRequestSuccess(object sender, GameEventArgs e) { WebRequestSuccessEventArgs ne = (WebRequestSuccessEventArgs)e; if (s_WebSerialIDs.Contains(ne.SerialId)) { if (ne.UserData is AwaitDataWrap webRequestUserdata) { WebResult result = WebResult.Create(ne.GetWebResponseBytes(), false, string.Empty, webRequestUserdata.UserData); s_DelayReleaseWebResult.Add(result); webRequestUserdata.Source.TrySetResult(result); ReferencePool.Release(webRequestUserdata); } s_WebSerialIDs.Remove(ne.SerialId); if (s_WebSerialIDs.Count == 0) { for (int i = 0; i < s_DelayReleaseWebResult.Count; i++) { ReferencePool.Release(s_DelayReleaseWebResult[i]); } s_DelayReleaseWebResult.Clear(); } } } private static void OnWebRequestFailure(object sender, GameEventArgs e) { WebRequestFailureEventArgs ne = (WebRequestFailureEventArgs)e; if (s_WebSerialIDs.Contains(ne.SerialId)) { if (ne.UserData is AwaitDataWrap webRequestUserdata) { WebResult result = WebResult.Create(null, true, ne.ErrorMessage, webRequestUserdata.UserData); webRequestUserdata.Source.TrySetResult(result); s_DelayReleaseWebResult.Add(result); ReferencePool.Release(webRequestUserdata); } s_WebSerialIDs.Remove(ne.SerialId); if (s_WebSerialIDs.Count == 0) { for (int i = 0; i < s_DelayReleaseWebResult.Count; i++) { ReferencePool.Release(s_DelayReleaseWebResult[i]); } s_DelayReleaseWebResult.Clear(); } } } /// /// 增加下载任务(可等待) /// public static Task AddDownloadAsync(this DownloadComponent downloadComponent, string downloadPath, string downloadUri, object userdata = null) { #if UNITY_EDITOR TipsSubscribeEvent(); #endif var tcs = new TaskCompletionSource(); int serialId = downloadComponent.AddDownload(downloadPath, downloadUri, AwaitDataWrap.Create(userdata, tcs)); s_DownloadSerialIds.Add(serialId); return tcs.Task; } private static void OnDownloadSuccess(object sender, GameEventArgs e) { DownloadSuccessEventArgs ne = (DownloadSuccessEventArgs)e; if (s_DownloadSerialIds.Contains(ne.SerialId)) { if (ne.UserData is AwaitDataWrap awaitDataWrap) { DownLoadResult result = DownLoadResult.Create(false, string.Empty, awaitDataWrap.UserData); s_DelayReleaseDownloadResult.Add(result); awaitDataWrap.Source.TrySetResult(result); ReferencePool.Release(awaitDataWrap); } s_DownloadSerialIds.Remove(ne.SerialId); if (s_DownloadSerialIds.Count == 0) { for (int i = 0; i < s_DelayReleaseDownloadResult.Count; i++) { ReferencePool.Release(s_DelayReleaseDownloadResult[i]); } s_DelayReleaseDownloadResult.Clear(); } } } private static void OnDownloadFailure(object sender, GameEventArgs e) { DownloadFailureEventArgs ne = (DownloadFailureEventArgs)e; if (s_DownloadSerialIds.Contains(ne.SerialId)) { if (ne.UserData is AwaitDataWrap awaitDataWrap) { DownLoadResult result = DownLoadResult.Create(true, ne.ErrorMessage, awaitDataWrap.UserData); s_DelayReleaseDownloadResult.Add(result); awaitDataWrap.Source.TrySetResult(result); ReferencePool.Release(awaitDataWrap); } s_DownloadSerialIds.Remove(ne.SerialId); if (s_DownloadSerialIds.Count == 0) { for (int i = 0; i < s_DelayReleaseDownloadResult.Count; i++) { ReferencePool.Release(s_DelayReleaseDownloadResult[i]); } s_DelayReleaseDownloadResult.Clear(); } } } } }