// Magica Cloth. // Copyright (c) MagicaSoft, 2020-2022. // https://magicasoft.jp using System.Collections.Generic; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.SceneManagement; namespace MagicaCloth { public static partial class BuildManager { //========================================================================================= /// /// MagicaClothコンポーネントの古い形式を最新にアップグレードする /// すでに最新の場合は何もしません /// Upgrading old formats of MagicaCloth components to the latest. /// If it is already up-to-date, do nothing. /// /// /// public static Define.Error UpgradeComponent(CoreComponent core) { Define.Error result = Define.Error.None; if (core == null) result = Define.Error.BuildInvalidComponent; if (core) { // プレハブかつシーンに配置されていない場合のみアセットに保存する string savePrefabPath = GetAssetSavePath(core); bool isPrefab = string.IsNullOrEmpty(savePrefabPath) == false; if (Define.IsNormal(result)) { var serializedObject = new SerializedObject(core); serializedObject.Update(); if (core.UpgradeFormat()) { // 更新あり serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(core); // 保存反映 if (isPrefab) AssetDatabase.SaveAssets(); if (Define.IsNormal(result)) Debug.Log($"[Upgrade] {core.name}"); } } } return result; } /// /// MagicaClothコンポーネントのデータ作成[Create]を実行する. /// Execute the MagicaCloth component's data creation [Create]. /// /// /// public static Define.Error CreateComponent(CoreComponent core) { Define.Error result = Define.Error.None; if (core == null) result = Define.Error.BuildInvalidComponent; if (core) { // プレハブかつシーンに配置されていない場合のみアセットに保存する string savePrefabPath = GetAssetSavePath(core); bool isPrefab = string.IsNullOrEmpty(savePrefabPath) == false; if (Define.IsNormal(result)) { //Debug.Log($"Started creating. [{core.name}] isPrefab:{isPrefab} path:{savePrefabPath}"); var serializedObject = new SerializedObject(core); serializedObject.Update(); // コンポーネント別データ作成 if (core is MagicaBoneCloth) result = CreateBoneCloth(core, serializedObject, savePrefabPath); else if (core is MagicaBoneSpring) result = CreateBoneSpring(core, serializedObject, savePrefabPath); else if (core is MagicaMeshCloth) result = CreateMeshCloth(core, serializedObject, savePrefabPath); else if (core is MagicaMeshSpring) result = CreateMeshSpring(core, serializedObject, savePrefabPath); else if (core is MagicaRenderDeformer) result = CreateRenderDeformer(core, serializedObject, savePrefabPath); else if (core is MagicaVirtualDeformer) result = CreateVirtualDeformer(core, serializedObject, savePrefabPath); // 最終検証結果 if (Define.IsNormal(result)) result = core.VerifyData(); // 保存反映 if (isPrefab) { AssetDatabase.SaveAssets(); } } } // 結果 if (result == Define.Error.None) Debug.Log($"[Creation] {core.name}"); else Debug.LogError($"[Creation] Failed! {core.name}\n{Define.GetErrorMessage(result)}"); return result; } /// /// 指定コンポーネントリストに対してデータ作成を実行する /// Execute data creation for the specified component list. /// /// /// /// public static BuildResult BuildFromComponents(List coreComponents, BuildOptions options) { if (coreComponents.Count == 0) return new BuildResult(Define.Error.Cancel); // ビルド順にソートする(特定の順序で実行しないとエラーとなる) SortCoreComponents(coreComponents); // ソート順にデータ作成 var result = new BuildResult(); foreach (var core in coreComponents) { //Debug.Log(core.name); var err = Define.Error.None; if (options.verificationOnly) { // 検証のみ if (IsOldFormat(core)) Debug.Log($"[Old Format] {core.name}"); if (IsOldAlgorithm(core)) Debug.Log($"[Old Algorithm] {core.name}"); var e = core.VerifyData(); if (e == Define.Error.EmptyData) Debug.Log($"[Not Created] {core.name}"); else if (Define.IsError(e)) Debug.Log($"[In Error] {core.name}\n{Define.GetErrorMessage(e)}"); //if (IsNotCreated(core)) // Debug.Log($"[Not created or in error] {core.name}"); } else { // 構築 // アップグレード if (options.upgradeFormatAndAlgorithm && (IsOldFormat(core) || IsOldAlgorithm(core))) { err = UpgradeComponent(core); if (Define.IsError(err)) { result.SetError(err); //Debug.LogError(Define.GetErrorMessage(err)); // エラー時の停止 if (options.errorStop) break; } } // 構築 err = CreateComponent(core); if (Define.IsError(err)) { result.SetError(err); //Debug.LogError(Define.GetErrorMessage(err)); // エラー時の停止 if (options.errorStop) break; } if (Define.IsNormal(err)) result.SetSuccess(); } } return result; } //========================================================================================= /// /// シーンのオブジェクトに対してデータ作成を実行する /// Perform data creation on objects in the scene. /// /// /// /// public static BuildResult BuildFromSceneObject(GameObject gobj, BuildOptions options) { if (gobj == null) return new BuildResult(Define.Error.BuildInvalidGameObject); if (gobj.scene.IsValid() == false) return new BuildResult(Define.Error.BuildNotSceneObject); var result = new BuildResult(); // 全コンポーネント取得 var coreComponents = new List(); GetBuildComponents(gobj, options, coreComponents); if (coreComponents.Count > 0) { Debug.Log($"[GameObject] {gobj.name}"); // ビルド result = BuildFromComponents(coreComponents, options); } return result; } /// /// プレハブアセットに対してすべてのデータ作成を実行する /// Perform all data creation for prefab assets. /// /// /// /// public static BuildResult BuildFromAssetPath(string path, BuildOptions options) { var prefab = AssetDatabase.LoadAssetAtPath(path); if (prefab == null) return new BuildResult(Define.Error.BuildInvalidPrefab); // 編集不可のプレハブならば保存できないため処理を行わない if (PrefabUtility.IsPartOfImmutablePrefab(prefab)) return new BuildResult(Define.Error.Cancel); var result = new BuildResult(); // 全コンポーネント取得 var coreComponents = new List(); GetBuildComponents(prefab, options, coreComponents); if (coreComponents.Count > 0) { Debug.Log($"[Prefab] {path}"); // スクリプトの欠損(missing)がある場合は保存できないためエラー if (options.verificationOnly == false && CheckMissingScripts(prefab)) return new BuildResult(Define.Error.BuildMissingScriptOnPrefab); // ビルド result.Merge(BuildFromComponents(coreComponents, options)); // サブアセットクリーンアップ if (result.SuccessCount > 0 && options.verificationOnly == false) ShareDataPrefabExtension.CleanUpSubAssets(prefab, log: false); } return result; } /// /// シーンの内部オブジェクトに対してすべてのデータ構築を実行する /// Perform all data construction for the scene's internal objects. /// /// /// /// public static BuildResult BuildFromScenePath(string path, BuildOptions options) { Scene targetScene = new Scene(); bool isOpened = false; // 現在開かれているシーンから検索 for (int i = 0; i < SceneManager.sceneCount; i++) { var scene = SceneManager.GetSceneAt(i); if (scene.path == path) { targetScene = scene; isOpened = true; } } if (isOpened == false) { targetScene = EditorSceneManager.OpenScene(path, OpenSceneMode.Additive); } if (targetScene.IsValid() == false) return new BuildResult(Define.Error.BuildInvalidScene); Debug.Log($"[Scene] {path}"); // すべてのコンポーネントを収集する var coreComponents = new List(); foreach (var go in targetScene.GetRootGameObjects()) GetBuildComponents(go, options, coreComponents); var result = new BuildResult(); if (coreComponents.Count > 0) { // ビルド result.Merge(BuildFromComponents(coreComponents, options)); // 1つ以上ビルドが成功した場合はシーンを保存する if (result.SuccessCount > 0 && options.verificationOnly == false) { EditorSceneManager.SaveScene(targetScene); } } if (isOpened == false) EditorSceneManager.CloseScene(targetScene, true); return result; } } }