JJBB/Assets/Editor/Scripts/SceneDisassembly.cs
2024-08-23 15:49:34 +08:00

843 lines
33 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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<GameObject> _parentGameObjects = new List<GameObject>();
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<Tab_SceneClass>();
_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是循环关联的
// 第一次创建场景资源然后创建新的LightingDataLightingData关联场景资源然后替换场景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<MeshCollider>(a => a.sharedMesh == null);
DestroyComponentByCondition<Animator>(a => a.runtimeAnimatorController == null);
DestroyComponentByCondition<Light>(a => a.type != LightType.Directional);
DestroyComponentByCondition<MeshRenderer>(a =>
{
var filter = a.GetComponent<MeshFilter>();
return filter == null || filter.sharedMesh == null;
});
DestroyComponentByCondition<SkinnedMeshRenderer>(a =>
a.sharedMesh == null || a.rootBone == null || a.bones == null || a.bones.Length < 1);
DestroyComponentByCondition<T4MObjSC>(a => true);
var rootObjects = _oldScene.GetRootGameObjects();
for (var i = 0; i < rootObjects.Length; i++)
MoveGameObjectToNewScene(rootObjects[i].transform);
}
private static void TweakComponent<T>(UnityAction<T> action) where T : Component
{
var components = Object.FindObjectsOfType<T>();
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<Renderer>(a =>
{
// 保留一些动画的投影能力
if (!(a is SkinnedMeshRenderer))
{
a.shadowCastingMode = ShadowCastingMode.Off;
a.receiveShadows = a is MeshRenderer;
}
a.allowOcclusionWhenDynamic = false;
a.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion;
});
TweakComponent<Light>(a =>
{
a.lightmapBakeType = LightmapBakeType.Mixed;
a.shadows = LightShadows.Soft;
a.shadowResolution = LightShadowResolution.High;
//// 仅仅用于将主角影子投射到地面
a.cullingMask = LayerMask.GetMask("MainPlayer") | ActiveScene.terrainLayMask;
});
// 修复一个可能导致无动画SkinnedMeshRenderer骨骼丢失的情况 - 该情况下本身蒙皮也无法运动
TweakComponent<SkinnedMeshRenderer>(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>();
// 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<LightingDataAsset>(lightingDataPath);
var serializedObject = new SerializedObject(lightingData);
var property = serializedObject.FindProperty("m_Scene");
var newSceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(_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<Component>();
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<T>(Transform root, string parentName) where T : Component
{
var result = root.GetComponent<T>();
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<SceneLogic>();
if (sceneLogic != null)
{
parentName = string.Empty;
moveChildren = false;
}
}
if (parentName == null)
parentName = CheckComponent<Light>(root, itemRootLight);
if (parentName == null)
{
var animator = root.GetComponent<Animator>();
if (animator != null && animator.isActiveAndEnabled)
{
// 特殊处理带有Animator的物体不能分解物体本身
var renderers = animator.GetComponentsInChildren<Renderer>();
// 不具有Renderer的Animator直接执行摧毁
if (renderers.Length > 0)
{
moveChildren = false;
parentName = itemRootAnimator;
}
}
}
if (parentName == null)
parentName = CheckComponent<ParticleSystem>(root, itemRootParticle);
if (parentName == null)
{
var renderer = root.GetComponent<Renderer>();
if (renderer != null && renderer.enabled && renderer.gameObject.activeInHierarchy &&
!root.HasComponent<NavMeshObject>())
parentName = itemRootSceneObj;
}
if (parentName == null)
parentName = CheckComponent<Collider>(root, itemRootCollider);
if (parentName == null)
parentName = CheckComponent<MovieEventRecv>(root, itemRootMisc);
if (parentName == null)
{
parentName = CheckComponent<DailyCopySceneAnimCtr>(root, itemRootMisc);
if (!string.IsNullOrEmpty(parentName))
moveChildren = false;
}
List<Transform> children = null;
if (moveChildren)
{
children = new List<Transform>();
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<T>(Predicate<T> condition) where T : Component
{
var components = Object.FindObjectsOfType<T>();
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<SceneAssembly>();
// GameObject sceneAssemblyObj;
// if (sceneAssembly != null)
// {
// sceneAssemblyObj = sceneAssembly.gameObject;
// Object.DestroyImmediate(sceneAssembly);
// }
// else
// sceneAssemblyObj = new GameObject("Scene Assembly");
// sceneAssembly = sceneAssemblyObj.AddComponent<SceneAssembly>();
// sceneAssembly.sceneObjs = new List<SceneObjData>();
// sceneAssembly.sceneMeshes = new List<SceneMeshData>();
// 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<GameObject>();
// 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<Renderer>();
// 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<SceneArea>();
// areaComponent.InitAreaData();
// PrefabUtility.CreatePrefab(areaPath.Open(rootItem.name + ".prefab"), rootItem);
// Object.DestroyImmediate(rootItem);
// }
// }
// private static void SetStaticUntilAnimator(Transform transform)
// {
// var animator = transform.GetComponent<Animator>();
// if (animator == null)
// {
// transform.gameObject.isStatic = transform.GetComponent<ParticleSystem>() == 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<ParticleSystem>();
// if (particle != null)
// {
// // 可以正确获得渲染边界
// particle.Simulate(1f);
// var particleRenderer = particle.GetComponent<ParticleSystemRenderer>();
// selfBounds = particleRenderer.bounds;
// var main = particle.main;
// main.playOnAwake = false;
// }
// else
// {
// var renderer = parent.GetComponent<Renderer>();
// 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<SceneHashRecord> GetHashRecord()
{
var hashList = new List<SceneHashRecord>();
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<string> _sceneList;
private int _sceneIndex;
private SceneDisassembly _current;
public DisassembleAllScenesAction(List<string> sceneList)
{
_sceneList = sceneList;
}
public event UnityAction<bool, DisassembleAllScenesAction> 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);
}
}
}