Files
JJBB/Assets/Editor/Scripts/SceneDisassembly.cs

843 lines
33 KiB
C#
Raw Normal View History

2024-08-23 15:49:34 +08:00
// 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);
}
}
}