// Scene材质会单独加载Bundle,一般物体则按GameObject流程加载。 // Scene被分解后,非平行光和其他非运行时物体都直接抛弃;Renderer材质全部修改为白模; // 运行时,按照九宫格流程加载所需资源;加载完成材质后,替换当前Renderer中的白模材质; // 模型网格会按照场景需求进行复制;材质、着色器和贴图会按照独一无二方式处理; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Cryptography; using System.Text; using Games.Scene; using GCGame.Table; using NavMeshExtension; using UnityEditor; using UnityEditor.SceneManagement; using UnityEngine; using UnityEngine.Events; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using Object = UnityEngine.Object; public class SceneDisassembly : EditorPerFrameActionBase { public const string sceneRoot = "Assets/Res_newMS/ChangJing/Sence"; public const string sceneDisassembledPath = "Assets/Project3D/BundleData/Scene"; //public const string roleSelectDir = sceneRoot + "/"; //+ GlobeVar.sceneRoleSelect; //public const string roleSelectTargetDir = sceneDisassembledPath + "/" + GlobeVar.sceneRoleSelect; public const string itemRootLight = "Lights"; public const string itemRootAnimator = "Animators"; public const string itemRootParticle = "Particles"; public const string itemRootSceneObj = "SceneObjs"; public const string itemRootCollider = "OtherColliders"; public const string itemRootMisc = "MiscItems"; public const string sceneExtension = ".unity"; private readonly List _parentGameObjects = new List(); private readonly string _sceneAssetPath; private readonly string _sceneName; private readonly string _targetAssetPath; private SceneDisassemblyProcess _index; private Scene _newScene; private Scene _oldScene; private Tab_SceneClass _sceneClass; public SceneDisassembly(string sceneAssetPath) { _index = SceneDisassemblyProcess.End; var fullSceneName = Path.GetFileName(sceneAssetPath); _sceneName = Path.GetFileNameWithoutExtension(fullSceneName); _sceneAssetPath = sceneAssetPath; _targetAssetPath = sceneDisassembledPath.Open(fullSceneName); _index = 0; } protected override int GetCurrentIndex() { return (int) _index; } protected override int GetTotalCount() { return (int) SceneDisassemblyProcess.End; } protected override void PerFrameAction() { switch (_index) { case SceneDisassemblyProcess.Open: // 异常防御机制 var temp = _index; _index = SceneDisassemblyProcess.End; var sceneClass = EditorTableManager.GetTable(); _sceneClass = sceneClass.Find(a => a.ResName.Equals(_sceneName, StringComparison.OrdinalIgnoreCase)); if (_sceneClass != null) { // 检查场景Hash,如果匹配就不执行分解 var lastHash = GetLastSceneHash(_sceneAssetPath); var currentHash = GetCurrentScenePath(_sceneAssetPath); if (lastHash != currentHash) { _oldScene = EditorSceneManager.OpenScene(_sceneAssetPath, OpenSceneMode.Single); if (_oldScene.isLoaded) _index = temp + 1; else Debug.LogError("场景加载失败 " + _sceneName); } else Debug.LogWarning("场景 " + _sceneName + " Hash匹配,跳过分解流程!"); } else { Debug.LogError("场景数据获得失败 " + _sceneName); } break; case SceneDisassemblyProcess.Create: _newScene = EditorSceneManager.NewScene(NewSceneSetup.EmptyScene, NewSceneMode.Additive); _index++; break; case SceneDisassemblyProcess.Disassemble: MoveSceneObjs(); SwapSceneObjs(); EditorSceneManager.CloseScene(_newScene, true); _index++; break; case SceneDisassemblyProcess.CreateLightData: // 注:确实需要保存两次,因为SceneAsset和LightingDataAsset是循环关联的 // 第一次创建场景资源;然后创建新的LightingData,LightingData关联场景资源;然后替换场景LightningData后再保存场景 EditorSceneManager.SaveScene(_oldScene, _targetAssetPath); CreateLightingData(); _index++; break; case SceneDisassemblyProcess.CreateAreas: FinalTweaks(); CheckUnexpected(); BuiltinAssetBuilder.ReplaceForOneScene(_oldScene); RemoveAreaAssets(); _index++; break; case SceneDisassemblyProcess.Save: // 分解结束后第二次保存 EditorSceneManager.SaveScene(_oldScene, _targetAssetPath); WriteSceneHash(_sceneAssetPath); _index++; break; default: _index++; break; } } private void MoveSceneObjs() { // 预先移除出现故障的组件 DestroyComponentByCondition(a => a.sharedMesh == null); DestroyComponentByCondition(a => a.runtimeAnimatorController == null); DestroyComponentByCondition(a => a.type != LightType.Directional); DestroyComponentByCondition(a => { var filter = a.GetComponent(); return filter == null || filter.sharedMesh == null; }); DestroyComponentByCondition(a => a.sharedMesh == null || a.rootBone == null || a.bones == null || a.bones.Length < 1); DestroyComponentByCondition(a => true); var rootObjects = _oldScene.GetRootGameObjects(); for (var i = 0; i < rootObjects.Length; i++) MoveGameObjectToNewScene(rootObjects[i].transform); } private static void TweakComponent(UnityAction action) where T : Component { var components = Object.FindObjectsOfType(); for (var i = 0; i < components.Length; i++) action.Invoke(components[i]); } private void SwapSceneObjs() { var oldRoots = _oldScene.GetRootGameObjects(); var newRoots = _newScene.GetRootGameObjects(); for (var i = 0; i < newRoots.Length; i++) SceneManager.MoveGameObjectToScene(newRoots[i], _oldScene); for (var i = 0; i < oldRoots.Length; i++) Object.DestroyImmediate(oldRoots[i]); } private void FinalTweaks() { var rootItems = _oldScene.GetRootGameObjects(); for (var i = 0; i < rootItems.Length; i++) PurgeAssets.PurgeOneGameObject(rootItems[i].transform); // 非Unity内置材质切换到空白材质 TweakComponent(a => { // 保留一些动画的投影能力 if (!(a is SkinnedMeshRenderer)) { a.shadowCastingMode = ShadowCastingMode.Off; a.receiveShadows = a is MeshRenderer; } a.allowOcclusionWhenDynamic = false; a.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; }); TweakComponent(a => { a.lightmapBakeType = LightmapBakeType.Mixed; a.shadows = LightShadows.Soft; a.shadowResolution = LightShadowResolution.High; //// 仅仅用于将主角影子投射到地面 a.cullingMask = LayerMask.GetMask("MainPlayer") | ActiveScene.terrainLayMask; }); // 修复一个可能导致无动画SkinnedMeshRenderer骨骼丢失的情况 - 该情况下本身蒙皮也无法运动 TweakComponent(a => { a.skinnedMotionVectors = false; var error = a.rootBone == null; if (!error) for (var i = 0; i < a.bones.Length; i++) if (a.bones[i] == null) { error = true; break; } if (error) { a.rootBone = null; a.bones = new Transform[0]; } }); var lightRoot = GameObject.Find(itemRootLight); if (lightRoot != null) lightRoot.SetStaticRecursively(false); var particleRoot = GameObject.Find(itemRootParticle); if (particleRoot != null) particleRoot.SetStaticRecursively(false); var animatorRoot = GameObject.Find(itemRootAnimator); if (animatorRoot != null) animatorRoot.SetStaticRecursively(false); var sceneObjRoot = GameObject.Find(itemRootSceneObj); if (sceneObjRoot != null) sceneObjRoot.SetStaticRecursively(true); var colliderRoot = GameObject.Find(itemRootCollider); if (colliderRoot != null) colliderRoot.SetStaticRecursively(true); RenderSettings.skybox = null; // var cameraRoot = new GameObject("CameraRoot"); // var cameraObj = new GameObject("Main Camera") {tag = "MainCamera"}; // cameraObj.transform.SetParent(cameraRoot.transform); // var camera = cameraObj.AddComponent(); // camera.allowHDR = false; // camera.useOcclusionCulling = false; // camera.allowMSAA = false; } private void CreateLightingData() { var lightingData = Lightmapping.lightingDataAsset; var sourcePath = AssetDatabase.GetAssetPath(lightingData); var extension = Path.GetExtension(sourcePath); var index = _targetAssetPath.LastIndexOf('.'); var lightingDataPath = index < 0 ? _targetAssetPath + extension : _targetAssetPath.Remove(index) + extension; if (AssetDatabase.CopyAsset(sourcePath, lightingDataPath)) { lightingData = AssetDatabase.LoadAssetAtPath(lightingDataPath); var serializedObject = new SerializedObject(lightingData); var property = serializedObject.FindProperty("m_Scene"); var newSceneAsset = AssetDatabase.LoadAssetAtPath(_targetAssetPath); property.objectReferenceValue = newSceneAsset; serializedObject.ApplyModifiedProperties(); EditorUtility.SetDirty(lightingData); Lightmapping.lightingDataAsset = lightingData; } else Debug.LogError("Lighting Data Asset Copy Failed!"); } private void CheckUnexpected() { var components = Object.FindObjectsOfType(); for (var i = 0; i < components.Length; i++) { var component = components[i]; if (!(component is Renderer) && !(component is Transform) && !(component is MeshFilter) && !(component is Collider) && !(component is Camera) && !(component is SceneLogic) && !(component is Light) && !(component is Animator) && !(component is ParticleSystem) && !(component is FogDensityLerp) && !(component is DirectionalLightSetter) && //!(component is uv_l_r) && //!(component is uv_u_d) && !(component is SceneObjItem) && !(component is MovieEventRecv) && !(component is AddChildAsset) && !(component is DailyCopySceneAnimCtr) && !(component is LoginShow) && !(component is ObjectRotate)) Debug.LogError("Unexpected Component " + component.GetType() + " on item " + component.transform.GetHierarchyName()); } } private string CheckComponent(Transform root, string parentName) where T : Component { var result = root.GetComponent(); if (result != null) { var mono = result as MonoBehaviour; if ((mono == null || mono.enabled) && result.gameObject.activeInHierarchy) return parentName; } return null; } private void MoveGameObjectToNewScene(Transform root) { if (!root.gameObject.activeInHierarchy) return; var moveChildren = true; // parentName == null表示不需要移动 string parentName = null; if (parentName == null) { var sceneLogic = root.GetComponent(); if (sceneLogic != null) { parentName = string.Empty; moveChildren = false; } } if (parentName == null) parentName = CheckComponent(root, itemRootLight); if (parentName == null) { var animator = root.GetComponent(); if (animator != null && animator.isActiveAndEnabled) { // 特殊处理带有Animator的物体,不能分解物体本身 var renderers = animator.GetComponentsInChildren(); // 不具有Renderer的Animator直接执行摧毁 if (renderers.Length > 0) { moveChildren = false; parentName = itemRootAnimator; } } } if (parentName == null) parentName = CheckComponent(root, itemRootParticle); if (parentName == null) { var renderer = root.GetComponent(); if (renderer != null && renderer.enabled && renderer.gameObject.activeInHierarchy && !root.HasComponent()) parentName = itemRootSceneObj; } if (parentName == null) parentName = CheckComponent(root, itemRootCollider); if (parentName == null) parentName = CheckComponent(root, itemRootMisc); if (parentName == null) { parentName = CheckComponent(root, itemRootMisc); if (!string.IsNullOrEmpty(parentName)) moveChildren = false; } List children = null; if (moveChildren) { children = new List(); var childCount = root.childCount; for (var i = childCount - 1; i >= 0; i--) { var child = root.GetChild(i); children.Add(child); if (parentName != null) { RemovePrefab(child.gameObject); child.SetParent(null); } } } if (parentName != null) { RemovePrefab(root.gameObject); if (string.IsNullOrEmpty(parentName)) { root.SetParent(null); SceneManager.MoveGameObjectToScene(root.gameObject, _newScene); } else { var parentObj = _parentGameObjects.Find(a => a.name == parentName); if (parentObj == null) { parentObj = new GameObject(parentName); if (parentObj.scene != _newScene) SceneManager.MoveGameObjectToScene(parentObj, _newScene); _parentGameObjects.Add(parentObj); } root.SetParent(null); SceneManager.MoveGameObjectToScene(root.gameObject, _newScene); root.SetParent(parentObj.transform); } } if (children != null) foreach (var child in children) MoveGameObjectToNewScene(child); } private static void DestroyComponentByCondition(Predicate condition) where T : Component { var components = Object.FindObjectsOfType(); for (var i = 0; i < components.Length; i++) if (condition.Invoke(components[i])) Object.DestroyImmediate(components[i]); } // Didn't remove the interface to make grammar check possible private static void RemovePrefab(GameObject item) { #if UNITY_2018_1_OR_NEWER var prefabRoot = PrefabUtility.GetNearestPrefabInstanceRoot(item); if (prefabRoot != null) PrefabUtility.UnpackPrefabInstance(prefabRoot, PrefabUnpackMode.Completely, InteractionMode.AutomatedAction); #endif } #region 分解场景物体流程 private void RemoveAreaAssets() { var areaPath = sceneDisassembledPath.Open(_oldScene.name); var removeAssets = (from assetPath in AssetDatabase.GetAllAssetPaths() where assetPath.StartsWith(areaPath + "/") select assetPath).ToArray(); for (var i = 0; i < removeAssets.Length; i++) { EditorUtility.DisplayProgressBar(title, string.Format("Delete Scene Asset: {0} / {1}", i, removeAssets.Length), (float)i / removeAssets.Length); AssetDatabase.DeleteAsset(removeAssets[i]); } } // private void CreateAreas() // { // var permanentLayer = LayerMask.NameToLayer("T4MLayer"); // // 切割场景区域块 - 因为需要维护分解和非分解两个流程,暂时不合并两次Transform移动 // var particleRoot = GameObject.Find(itemRootParticle); // if (particleRoot != null) // CreateForOneRoot(particleRoot.transform, permanentLayer); // var meshRoot = GameObject.Find(itemRootSceneObj); // if (meshRoot != null) // CreateForOneRoot(meshRoot.transform, permanentLayer); // var animRoot = GameObject.Find(itemRootAnimator); // if (animRoot != null) // CreateForOneRoot(animRoot.transform, permanentLayer); // var sceneAssembly = Object.FindObjectOfType(); // GameObject sceneAssemblyObj; // if (sceneAssembly != null) // { // sceneAssemblyObj = sceneAssembly.gameObject; // Object.DestroyImmediate(sceneAssembly); // } // else // sceneAssemblyObj = new GameObject("Scene Assembly"); // sceneAssembly = sceneAssemblyObj.AddComponent(); // sceneAssembly.sceneObjs = new List(); // sceneAssembly.sceneMeshes = new List(); // var rootItems = _oldScene.GetRootGameObjects(); // var areaPath = sceneDisassembledPath.Open(_oldScene.name); // if (!AssetDatabase.IsValidFolder(areaPath)) // AssetDatabase.CreateFolder(sceneDisassembledPath, _oldScene.name); // AssetDatabase.Refresh(); // GameObject indieRoot = null; // var areaRoots = new List(); // for (var i = 0; i < rootItems.Length; i++) // { // var rootItem = rootItems[i]; // if (rootItem.name == itemRootIndie) // indieRoot = rootItem; // else if (rootItem.name.StartsWith("Area_")) // areaRoots.Add(rootItem); // else // SetStaticUntilAnimator(rootItem.transform); // } // if (indieRoot != null) // { // var index = 0; // var total = indieRoot.transform.childCount; // foreach (Transform child in indieRoot.transform) // { // EditorUtility.DisplayProgressBar(title, string.Format("Create Indie Item: {0} / {1}", index, total), (float)index / total); // child.name = string.Format(itemIndieFormat, index); // var meshRenderer = child.GetComponent(); // var bounds = meshRenderer.bounds; // var indie = new SceneMeshData // { // bundlePath = GetAreaBundleName(_oldScene.name, child.name), // assetName = child.name, // localPosition = child.localPosition, // localRotation = child.localRotation, // localScale = child.localScale, // lightmapIndex = meshRenderer.lightmapIndex, // lightmapScaleOffset = meshRenderer.lightmapScaleOffset, // bounds = new Circle { center = bounds.center.RemoveY(), radius = bounds.extents.RemoveY().magnitude } // }; // sceneAssembly.sceneMeshes.Add(indie); // PrefabUtility.CreatePrefab(areaPath.Open(child.gameObject.name + ".prefab"), child.gameObject); // index++; // } // Object.DestroyImmediate(indieRoot); // } // for (var i = 0; i < areaRoots.Count; i++) // { // var rootItem = areaRoots[i]; // EditorUtility.DisplayProgressBar(title, string.Format("Create Area: {0} / {1}", i, areaRoots.Count), (float)i / areaRoots.Count); // var bounds = new Bounds(); // GetAreaBounds(ref bounds, rootItem.transform); // var area = new SceneObjData // { // bundlePath = GetAreaBundleName(_oldScene.name, rootItem.name), // assetName = rootItem.name, // localPosition = rootItem.transform.localPosition, // localRotation = rootItem.transform.localRotation, // localScale = rootItem.transform.localScale, // bounds = new Circle { center = bounds.center.RemoveY(), radius = bounds.extents.RemoveY().magnitude } // }; // if (area.bounds.radius > _itemAreaLength) // Debug.LogWarning("Scene " + _oldScene.name + " " + rootItem.name + " has a radius of " + area.bounds.radius); // sceneAssembly.sceneObjs.Add(area); // rootItem.SetStaticRecursively(false); // var areaComponent = rootItem.AddComponent(); // areaComponent.InitAreaData(); // PrefabUtility.CreatePrefab(areaPath.Open(rootItem.name + ".prefab"), rootItem); // Object.DestroyImmediate(rootItem); // } // } // private static void SetStaticUntilAnimator(Transform transform) // { // var animator = transform.GetComponent(); // if (animator == null) // { // transform.gameObject.isStatic = transform.GetComponent() == null; // foreach (Transform child in transform) // SetStaticUntilAnimator(child); // } // } // private void CreateForOneRoot(Transform root, int permanentLayer) // { // var childCount = root.childCount; // for (var i = childCount - 1; i >= 0; i--) // { // var child = root.GetChild(i); // if (child.gameObject.layer == permanentLayer) // MoveAreaItemToParent(child, itemRootPermanent); // else // { // var bounds = new Bounds(); // GetAreaBounds(ref bounds, child); // CreateOneAreaItem(child, bounds); // } // } // if (root.childCount <= 0) // Object.DestroyImmediate(root.gameObject); // } // public static string GetAreaBundleName(string sceneName, string areaName) // { // sceneName = Path.GetFileNameWithoutExtension(sceneName); // areaName = Path.GetFileNameWithoutExtension(areaName); // return string.Format(sceneAreaBundleFormat, sceneName, areaName).ToLower(); // } // // private void CreateOneAreaItem(Transform item, Bounds bounds) // { // // 检测物体尺寸是否应该作为独立物体 // var rootName = bounds.size.x > _indieItemLength || bounds.size.y > _indieItemLength || // bounds.size.z > _indieItemLength // ? itemRootIndie // : PositionToAreaName(bounds.center); // MoveAreaItemToParent(item, rootName); // } // private void MoveAreaItemToParent(Transform item, string rootName) // { // var rootObj = GameObject.Find(rootName); // if (rootObj == null) // rootObj = new GameObject(rootName); // item.SetParent(rootObj.transform); // } // // private string PositionToAreaName(Vector3 position) // { // var x = Mathf.FloorToInt((position.x - _sceneClass.BasePosX) / _itemAreaLength); // var z = Mathf.FloorToInt((position.z - _sceneClass.BasePosZ) / _itemAreaLength); // // 防止负号导致超链接无法生成 // unchecked // { // return string.Format(itemRootAreaFormat, (uint)x, (uint)z); // } // } // // private void GetAreaBounds(ref Bounds bounds, Transform parent) // { // Bounds? selfBounds = null; // var particle = parent.GetComponent(); // if (particle != null) // { // // 可以正确获得渲染边界 // particle.Simulate(1f); // var particleRenderer = particle.GetComponent(); // selfBounds = particleRenderer.bounds; // var main = particle.main; // main.playOnAwake = false; // } // else // { // var renderer = parent.GetComponent(); // if (renderer != null) // selfBounds = renderer.bounds; // } // // if (selfBounds != null) // { // if (bounds.size.x <= 0f) // bounds = selfBounds.Value; // else // bounds.Encapsulate(selfBounds.Value); // } // // foreach (Transform child in parent) // GetAreaBounds(ref bounds, child); // } #endregion #region 读取和写入源场景Hash值 public const string sceneHashPath = "sceneHash.txt"; public static string GetCurrentScenePath(string scenePath) { var filePath = Application.dataPath.MoveUp().Open(scenePath); var result = string.Empty; if (File.Exists(filePath)) { var md5 = MD5.Create(); byte[] hash; using (var fs = File.OpenRead(filePath)) hash = md5.ComputeHash(fs); result = BitConverter.ToString(hash); } return result; } public static string GetLastSceneHash(string scenePath) { var hashList = GetHashRecord(); var sceneName = Path.GetFileNameWithoutExtension(scenePath); var hash = string.Empty; for (var i = 0; i < hashList.Count; i++) { if (hashList[i].sceneName == sceneName) { hash = hashList[i].sceneHash; break; } } return hash; } public static void WriteSceneHash(string scenePath) { var hashList = GetHashRecord(); var sceneName = Path.GetFileNameWithoutExtension(scenePath); var sceneHash = GetCurrentScenePath(scenePath); var add = true; for (var i = 0; i < hashList.Count; i++) { if (hashList[i].sceneName == sceneName) { sceneHash = hashList[i].sceneHash = sceneHash; add = false; break; } } if (add) hashList.Add(new SceneHashRecord(sceneName, sceneHash)); var builder = new StringBuilder(); for (var i = 0; i < hashList.Count; i++) hashList[i].AppendLine(builder); var filePath = Application.dataPath.MoveUp().Open(sceneDisassembledPath).Open(sceneHashPath); var diretory = Path.GetDirectoryName(filePath); if (!Directory.Exists(diretory)) // ReSharper disable once AssignNullToNotNullAttribute Directory.CreateDirectory(diretory); File.WriteAllText(filePath, builder.ToString()); } private static List GetHashRecord() { var hashList = new List(); var filePath = Application.dataPath.MoveUp().Open(sceneDisassembledPath).Open(sceneHashPath); if (File.Exists(filePath)) { var lines = File.ReadAllLines(filePath); for (var i = 0; i < lines.Length; i++) { var hash = SceneHashRecord.CreateFromLine(lines[i]); if (hash != null) hashList.Add(hash); } } return hashList; } #endregion private enum SceneDisassemblyProcess { Open, Create, Disassemble, CreateLightData, CreateAreas, Save, End } private class SceneHashRecord { public string sceneName; public string sceneHash; public static SceneHashRecord CreateFromLine(string line) { SceneHashRecord result = null; if (!string.IsNullOrEmpty(line)) { var segments = line.Split('\t'); if (segments.Length == 2) result = new SceneHashRecord(segments[0], segments[1]); } return result; } public void AppendLine(StringBuilder builder) { builder.AppendLine(sceneName + "\t" + sceneHash); } public SceneHashRecord(string sceneName, string sceneHash) { this.sceneName = sceneName; this.sceneHash = sceneHash; } } } public class DisassembleAllScenesAction { private readonly List _sceneList; private int _sceneIndex; private SceneDisassembly _current; public DisassembleAllScenesAction(List sceneList) { _sceneList = sceneList; } public event UnityAction onFinish; public void Start() { _sceneIndex = -1; // 2018.12.11 - RoleSelect不复制,而是直接使用源文件。之前流程会导致RoleSelect系列场景在Bundle中存在两份。 // 预先处理RoleSelect系列的场景 // 预先处理RoleSelect场景 //var roleSelectSubPaths = (from assetPath in AssetDatabase.GetAllAssetPaths() // where assetPath.StartsWith(SceneDisassembly.roleSelectDir + "/", StringComparison.OrdinalIgnoreCase) // where Path.GetExtension(assetPath) == SceneDisassembly.sceneExtension // select assetPath).ToArray(); //for (var i = 0; i < roleSelectSubPaths.Length; i++) //{ // var assetPath = roleSelectSubPaths[i]; // var scenePath = SceneDisassembly.roleSelectTargetDir.Open(Path.GetFileName(assetPath)); // var lastHash = SceneDisassembly.GetLastSceneHash(assetPath); // var currentHash = SceneDisassembly.GetCurrentScenePath(assetPath); // if (lastHash != currentHash) // { // var roleSelect = EditorSceneManager.OpenScene(assetPath); // BuiltinAssetBuilder.ReplaceForOneScene(roleSelect); // EditorSceneManager.SaveScene(roleSelect, scenePath); // SceneDisassembly.WriteSceneHash(assetPath); // } // else // Debug.LogWarning("选角场景 " + assetPath + " Hash匹配,跳过复制流程!"); //} OnCurrentFinish(true, null); } private void OnCurrentFinish(bool success, EditorPerFrameActionBase action) { var finish = false; if (success) { _sceneIndex++; if (_sceneIndex < _sceneList.Count) { var scenePath = SceneDisassembly.sceneRoot.Open(_sceneList[_sceneIndex]); _current = new SceneDisassembly(scenePath); _current.onFinish += OnCurrentFinish; _current.Start(); Debug.LogWarning("Start Scene " + _sceneIndex + " to " + scenePath); } else { finish = true; } } else { finish = true; } if (finish) { _current = null; if (success) { AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.LogWarning("All Scene Dissemble Finish"); } else Debug.LogError("Error in Scene Dissemble"); if (onFinish != null) onFinish(success, this); } } }