public static void DemoEditorCoroutines() { // adds a menu item to test the coroutine system. if (!Application.isPlaying) { // lets fire off the demo coroutine with a UI so we can see what its doing. We could also run it without a UI by using EditorCoroutineRunner.StartCoroutine(...) EditorCoroutineRunner.StartCoroutineWithUI(DemoCoroutiune(), "Lotte's Coroutine Demo", true); } }
static IEnumerator DemoCoroutiune() { // You can code editor coroutines exactly like you would a normal unity coroutine Debug.Log("Step: 0"); yield return(null); // all the normal return types that work with regular Unity coroutines should work here! for example lets wait for a second Debug.Log("Step: 1"); yield return(new WaitForSeconds(1)); // We can also yeild any type that extends Unitys CustomYieldInstruction class. here we are going to use EditorStatusUpdate. this allows us to yield and update the // editor coroutine UI at the same time! yield return(new EditorStatusUpdate("coroutine is running", 0.2f)); // We can also yield to nested coroutines Debug.Log("Step: 2"); yield return(EditorCoroutineRunner.StartCoroutine(DemoTwo())); EditorCoroutineRunner .UpdateUIProgressBar( 0.35f); // we can use the UpdateUI helper methods to update the UI whenever, without yielding a EditorStatusUpdate yield return (DemoTwo()); // it shouldnt matter how we start the nested coroutine, the editor runner can hadle it // we can even yield a WWW object if we want to grab data from the internets! Debug.Log("Step: 3"); // for example, lets as random.org to generate us a list of random numbers and shove it into the console var www = new WWW( "https://www.random.org/integers/?num=100&min=1&max=1000&col=1&base=10&col=5&format=plain&rnd=new"); yield return(www); Debug.Log(www.text); EditorCoroutineRunner.UpdateUI("Half way!", 0.5f); yield return(new WaitForSeconds(1)); // Finally lets do a long runnig task and split its updates over many frames to keep the editor responsive Debug.Log("Step: 4"); var test = 1000; yield return(new WaitUntil(() => { test--; EditorCoroutineRunner.UpdateUI("Crunching Numbers: " + test, 0.5f + (((1000 - test) / 1000f) * 0.5f)); return (test <= 0); })); Debug.Log("Done!!"); }
private static IEnumerator downloadAll(List <GSPluginSettings.Sheet> sheets, string settingDir) { float progress = 0f; int i = 0; foreach (var ss in sheets) { EditorCoroutineRunner.UpdateUILabel("Downloading " + ss.targetPath); yield return(EditorCoroutineRunner.StartCoroutine(Download(ss, settingDir))); progress = (float)(++i) / sheets.Count; EditorCoroutineRunner.UpdateUIProgressBar(progress); } AssetDatabase.Refresh(); }
public static IEnumerator ExecuteImport(ConvertSetting s) { downloadSuccess = false; yield return(EditorCoroutineRunner.StartCoroutine(ExecuteDownload(s))); if (!downloadSuccess) { yield break; } CreateAssetsJob createAssetsJob = new CreateAssetsJob(s); // Generate Code if type script is not found. Type assetType; if (s.isEnum || !CsvConvert.TryGetTypeWithError(s.className, out assetType, s.checkFullyQualifiedName, dialog: false)) { GlobalCCSettings gSettings = CCLogic.GetGlobalSettings(); GenerateOneCode(s, gSettings); if (!s.isEnum) { EditorUtility.DisplayDialog( "Code Generated", "Please reimport for creating assets after compiling", "ok" ); } } // Create Assets else { createAssetsJob.Execute(); } // AfterImport 処理 for (int i = 0; i < s.executeAfterImport.Count; i++) { var afterSettings = s.executeAfterImport[i]; if (afterSettings != null) { yield return(EditorCoroutineRunner.StartCoroutine(ExecuteImport(afterSettings))); } } }
public static IEnumerator ExecuteDownload(ConvertSetting s) { GSPluginSettings.Sheet sheet = new GSPluginSettings.Sheet(); sheet.sheetId = s.sheetID; sheet.gid = s.gid; GlobalCCSettings gSettings = CCLogic.GetGlobalSettings(); string csvPath = s.GetCsvPath(gSettings); if (string.IsNullOrWhiteSpace(csvPath)) { Debug.LogError("unexpected downloadPath: " + csvPath); downloadSuccess = false; yield break; } string absolutePath = CCLogic.GetFilePathRelativesToAssets(s.GetDirectoryPath(), csvPath); // 先頭の Assets を削除する if (absolutePath.StartsWith("Assets" + Path.DirectorySeparatorChar)) { sheet.targetPath = absolutePath.Substring(6); } else { Debug.LogError("unexpected downloadPath: " + absolutePath); downloadSuccess = false; yield break; } sheet.isCsv = true; sheet.verbose = false; string title = "Google Spreadsheet Loader"; yield return(EditorCoroutineRunner.StartCoroutineWithUI(GSEditorWindow.Download(sheet, s.GetDirectoryPath()), title, true)); // 成功判定を行う. if (GSEditorWindow.previousDownloadSuccess) { downloadSuccess = true; } yield break; }
/// <summary> /// 指定の sheetId, gid のシートを CsvData としてダウンロードする. /// /// Google Spreadsheet URL に2つのリクエストを送る。 /// まず一つ目は sheetId に対する複数の worksheet を持つ URL へのリクエスト。 /// 二つ目は その sheetId の中で特定の gid を持つ URL へのリクエスト。 /// </summary> public IEnumerator LoadGS(string sheetId, string gid, string apiKey = "", bool useV4 = true) { isSuccess = false; if (useV4) { var coroutine = GSLoaderV4.LoadCsvData(sheetId, gid, apiKey); yield return(coroutine); loadedCsvData = GSLoaderV4.csvData; isSuccess = loadedCsvData != null; } // V3 old api else { // Load spread sheet yield return(EditorCoroutineRunner.StartCoroutine(downloadWorksheets(sheetId))); if (_worksheets == null) { Debug.LogError("Failed to download worksheets"); yield break; } // Load each worksheet foreach (GSWorksheet sheet in _worksheets) { if (sheet.gid == gid) { yield return(EditorCoroutineRunner.StartCoroutine(LoadCsvData(sheet))); yield break; } } } }
public static IEnumerator Download(GSPluginSettings.Sheet ss, string settingDir) { previousDownloadSuccess = false; string sheetId = ss.sheetId; string gid = ss.gid; string label = "Downloading " + ss.targetPath; EditorCoroutineRunner.UpdateUILabel(label); var gsLoader = new GSLoader(); var globalSettings = CCLogic.GetGlobalSettings(); string apiKey = globalSettings.apiKey; bool useV4 = globalSettings.useV4; yield return(EditorCoroutineRunner.StartCoroutine(gsLoader.LoadGS(sheetId, gid, apiKey, useV4))); if (!gsLoader.isSuccess) { Debug.Log("Failed to load spreadsheet data."); yield break; } CsvData csvData = gsLoader.loadedCsvData; string targetPathRelativeToAssets = ss.GetFilePathRelativesToAssets(settingDir); if (csvData != null) { if (ss.isCsv) { string targetDir = Path.GetDirectoryName(targetPathRelativeToAssets); if (!Directory.Exists(targetDir)) { try { Directory.CreateDirectory(targetDir); Debug.Log("指定のフォルダが存在しないため、作成しました: " + targetDir); } catch (Exception e) { Debug.LogError("指定のフォルダの作成に失敗: " + e.Message); } // Debug.LogError("指定のフォルダは存在しません: " + targetDir); // return; } using (var s = new StreamWriter(targetPathRelativeToAssets)) { s.Write(csvData.ToString()); } } else { // AssetDatabase.CreateAsset(csvData, targetPathRelativeToAssets); Debug.LogError("CsvData の書き出しには未対応になりました"); } if (ss.verbose) { Debug.Log("Write " + ss.targetPath); } previousDownloadSuccess = true; AssetDatabase.Refresh(); } else { Debug.LogError("Fails for " + ss.ToString()); } }
public static void DownloadOne(GSPluginSettings.Sheet sheet, string settingPath) { string title = "Google Spreadsheet Loader"; EditorCoroutineRunner.StartCoroutineWithUI(Download(sheet, settingPath), title, true); }
private void DownloadAll(List <GSPluginSettings.Sheet> sheets, string settingDir) { string title = "Downloading All"; EditorCoroutineRunner.StartCoroutineWithUI(downloadAll(sheets, settingDir), title, true); }
private void OnGUI() { GUILayout.Space(6f); ConvertSetting[] settings = null; if (cachedAllSettings != null) { settings = cachedAllSettings; } // 検索ボックスを表示 GUILayout.BeginHorizontal(); searchTxt = SearchField(searchTxt); searchTxt = searchTxt.ToLower(); GUILayout.EndHorizontal(); if (settings != null) { scrollPosition = GUILayout.BeginScrollView(scrollPosition); for (int i = 0; i < settings.Length; i++) { var s = settings[i]; // 設定が削除されている場合などに対応 if (s == null) { continue; } // 検索ワードチェック if (!string.IsNullOrEmpty(searchTxt)) { if (s.tableGenerate) { if (!searchTxt.IsSubsequence(s.tableAssetName.ToLower())) { continue; } } else { if (!searchTxt.IsSubsequence(s.className.ToLower())) { continue; } } } GUILayout.BeginHorizontal("box"); #if ODIN_INSPECTOR // ------------------------------ // 設定を複製ボタン. // ------------------------------ if (GUILayout.Button("+", GUILayout.Width(20))) { var copied = s.Copy(); var window = CCSettingsEditWindow.OpenWindow(); window.SetNewSettings(copied, s.GetDirectoryPath()); GUIUtility.ExitGUI(); } // ------------------------------ // 設定を編集ボタン. // ------------------------------ var edit = EditorGUIUtility.Load("editicon.sml") as Texture2D; if (GUILayout.Button(edit, GUILayout.Width(20))) { var window = CCSettingsEditWindow.OpenWindow(); window.SetSettings(s); GUIUtility.ExitGUI(); } #endif // ------------------------------ // テーブル名 (enum の場合は enum名) を表示. // クリックして、設定ファイルに飛べるようにする. // ------------------------------ if (s.tableGenerate) { if (GUILayout.Button(s.tableAssetName, "Label")) { EditorGUIUtility.PingObject(s.GetInstanceID()); GUIUtility.ExitGUI(); } } else { if (GUILayout.Button(s.className, "Label")) { EditorGUIUtility.PingObject(s.GetInstanceID()); GUIUtility.ExitGUI(); } } // ------------------------------ // GS Plugin 使う場合のボタン. // // Import ボタン // Open ボタン // ------------------------------ if (s.useGSPlugin) { if (GUILayout.Button("Import", GUILayout.Width(110))) { EditorCoroutineRunner.StartCoroutine(ExecuteImport(s)); GUIUtility.ExitGUI(); } // GS Plugin を使う場合は Open ボタンを用意する. if (s.useGSPlugin) { if (GUILayout.Button("Open", GUILayout.Width(80)) && !isDownloading) { GSUtils.OpenURL(s.sheetID, s.gid); GUIUtility.ExitGUI(); } } if (s.verboseBtn) { if (GUILayout.Button("DownLoad", GUILayout.Width(110))) { EditorCoroutineRunner.StartCoroutine(ExecuteDownload(s)); GUIUtility.ExitGUI(); } } } // ------------------------------ // コード生成ボタン. // v0.1.2 からは Import に置き換え. // ------------------------------ if (s.verboseBtn) { GUI.enabled = s.canGenerateCode; if (GUILayout.Button("Generate Code", GUILayout.Width(110)) && !isDownloading) { GlobalCCSettings gSettings = CCLogic.GetGlobalSettings(); isDownloading = true; GenerateOneCode(s, gSettings); isDownloading = false; GUIUtility.ExitGUI(); } } // ------------------------------ // アセット生成ボタン. // v0.1.2 からは Import に置き換え. // ------------------------------ if (s.verboseBtn) { GUI.enabled = s.canCreateAsset; if (GUILayout.Button("Create Assets", GUILayout.Width(110)) && !isDownloading) { CreateAssetsJob createAssetsJob = new CreateAssetsJob(s); createAssetsJob.Execute(); GUIUtility.ExitGUI(); } } GUI.enabled = true; // ------------------------------ // 成果物参照まど. // ------------------------------ { Object outputRef = null; if (s.join) { outputRef = s.targetTable; } else { string mainOutputPath = CCLogic.GetMainOutputPath(s); if (mainOutputPath != null) { outputRef = AssetDatabase.LoadAssetAtPath <Object>(mainOutputPath); } } EditorGUI.BeginDisabledGroup(true); EditorGUILayout.ObjectField(outputRef, typeof(Object), false, GUILayout.Width(100)); EditorGUI.EndDisabledGroup(); } GUILayout.EndHorizontal(); } GUILayout.EndScrollView(); GUILayout.BeginHorizontal("box"); if (GUILayout.Button("Generate All Codes", "LargeButtonMid") && !isDownloading) { GlobalCCSettings gSettings = CCLogic.GetGlobalSettings(); isDownloading = true; GenerateAllCode(settings, gSettings); isDownloading = false; GUIUtility.ExitGUI(); } if (GUILayout.Button("Create All Assets", "LargeButtonMid") && !isDownloading) { GlobalCCSettings gSettings = CCLogic.GetGlobalSettings(); isDownloading = true; CreateAllAssets(settings, gSettings); isDownloading = false; GUIUtility.ExitGUI(); } GUILayout.EndHorizontal(); } }
public void Tick() { if (coroutine != null) { // First check if we have been canceled by the UI. If so, we need to stop before doing any wait processing if (canceled) { Stop(); return; } // Did the last Yield want us to wait? bool isWaiting = false; var now = DateTime.Now; if (current != null) { if (currentType == typeof(WaitForSeconds)) { // last yield was a WaitForSeconds. Lets update the timer. var delta = now - lastUpdateTime; timer -= (float)delta.TotalSeconds; if (timer > 0.0f) { isWaiting = true; } } else if (currentType == typeof(WaitForEndOfFrame) || currentType == typeof(WaitForFixedUpdate)) { // These dont make sense in editor, so we will treat them the same as a null return... isWaiting = false; } else if (currentType == typeof(WWW)) { // Web download request, lets see if its done! var www = current as WWW; if (!www.isDone) { isWaiting = true; } } else if (currentType.IsSubclassOf(typeof(CustomYieldInstruction))) { // last yield was a custom yield type, lets check its keepWaiting property and react to that var yieldInstruction = current as CustomYieldInstruction; if (yieldInstruction.keepWaiting) { isWaiting = true; } } else if (currentType == typeof(EditorCoroutine)) { // Were waiting on another coroutine to finish var editorCoroutine = current as EditorCoroutine; if (!editorCoroutine.HasFinished) { isWaiting = true; } } else if (typeof(IEnumerator).IsAssignableFrom(currentType)) { // if were just seeing an enumerator lets assume that were seeing a nested coroutine that has been passed in without calling start.. were start it properly here if we need to if (nestedCoroutine == null) { nestedCoroutine = EditorCoroutineRunner.StartCoroutine(current as IEnumerator); isWaiting = true; } else { isWaiting = !nestedCoroutine.HasFinished; } } else if (currentType == typeof(Coroutine)) { // UNSUPPORTED Debug.LogError( "Nested Coroutines started by Unity's defaut StartCoroutine method are not supported in editor! please use EditorCoroutineRunner.Start instead. Canceling."); canceled = true; } else { // UNSUPPORTED Debug.LogError("Unsupported yield (" + currentType + ") in editor coroutine!! Canceling."); canceled = true; } } lastUpdateTime = now; // have we been canceled? if (canceled) { Stop(); return; } if (!isWaiting) { // nope were good! tick the coroutine! bool update = coroutine.MoveNext(); if (update) { // yup the coroutine returned true so its been ticked... // lets see what it actually yielded current = coroutine.Current; if (current != null) { // is it a type we have to do extra processing on? currentType = current.GetType(); if (currentType == typeof(WaitForSeconds)) { // its a WaitForSeconds... lets use reflection to pull out how long the actual wait is for so we can process the wait var wait = current as WaitForSeconds; FieldInfo m_Seconds = typeof(WaitForSeconds).GetField("m_Seconds", BindingFlags.NonPublic | BindingFlags.Instance); if (m_Seconds != null) { timer = (float)m_Seconds.GetValue(wait); } } else if (currentType == typeof(EditorStatusUpdate)) { // Special case yield that wants to update the UI! var updateInfo = current as EditorStatusUpdate; if (updateInfo.HasLabelUpdate) { Label = updateInfo.Label; } if (updateInfo.HasPercentUpdate) { PercentComplete = updateInfo.PercentComplete; } } } } else { // Coroutine returned false so its finally finished!! Stop(); } } } }