Files
Main/Assets/Launcher/ExternalLibs/PrefabAssetData/PrefabAssetData.cs
2025-01-25 04:38:09 +08:00

469 lines
20 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
namespace Thousandto.Launcher.ExternalLibs
{
/// <summary>
/// Prefab的资源持续化脚本处理
/// </summary>
public class PrefabAssetData: UnityEngine.ScriptableObject
{
/// <summary>
/// 当前对象的名字
/// </summary>
public string Name;
/// <summary>
/// Prefab对象
/// </summary>
public GameObject PrefabObject;
/// <summary>
/// 渲染的资源信息
/// </summary>
public RenderAssetData[] RendererArray;
//动作资源信息
public AnimationAssetData[] AnimArray;
//动作资源信息
public AnimatorAssetData[] AnimtorArray;
//Timeline资源信息
public TimelineAssetData[] TimelineArray;
#region //运行时执行
//卸载资源
public void Unload()
{
/*
Debug.LogError("UnloadStart:" + Name + ";;内存:"
+ Profiler.GetTotalAllocatedMemory() / (1024 * 1024)
+ ";trm;" + Profiler.GetTotalReservedMemory() / (1024 * 1024)
+ ";turm;" + Profiler.GetTotalUnusedReservedMemory() / (1024 * 1024)
+ ";mus;" + Profiler.GetMonoUsedSize() / (1024 * 1024)
+ ";mhs;" + Profiler.GetMonoHeapSize() / (1024 * 1024)
);
var start = Time.realtimeSinceStartup;
*/
if (PrefabObject != null)
{
//删除Prefab
GameObject.DestroyImmediate(PrefabObject, true);
PrefabObject = null;
}
//删除资源
if (RendererArray != null)
{
for (int i = 0; i < RendererArray.Length; i++)
{
if (RendererArray[i] != null)
RendererArray[i].Unload();
}
}
RendererArray = null;
if (AnimArray != null)
{
for (int i = 0; i < AnimArray.Length; i++)
{
if (AnimArray[i] != null)
{
AnimArray[i].Unload();
}
}
}
AnimArray = null;
if(TimelineArray != null)
{
var cnt = TimelineArray.Length;
for (int i = 0; i < cnt; i++)
{
if (TimelineArray[i] != null)
{
TimelineArray[i].Unload();
}
}
}
TimelineArray = null;
/*
var duration = (Time.realtimeSinceStartup - start) * 1000;
Debug.LogError("UnloadFinished:" + Name + ";;;" + duration+ ";;内存:"
+ Profiler.GetTotalAllocatedMemory() / (1024 * 1024)
+ ";trm;" + Profiler.GetTotalReservedMemory() / (1024 * 1024)
+ ";turm;" + Profiler.GetTotalUnusedReservedMemory() / (1024 * 1024)
+ ";mus;" + Profiler.GetMonoUsedSize() / (1024 * 1024)
+ ";mhs;" + Profiler.GetMonoHeapSize() / (1024 * 1024)
);
*/
}
//获取预制对象
public GameObject ToPrefabGo()
{
if (PrefabObject != null)
{
/*
Debug.LogError("ToPrefabGo:" + Name + ";;内存:"
+ Profiler.GetTotalAllocatedMemory() / (1024 * 1024)
+ ";trm;" + Profiler.GetTotalReservedMemory() / (1024 * 1024)
+ ";turm;" + Profiler.GetTotalUnusedReservedMemory() / (1024 * 1024)
+ ";mus;" + Profiler.GetMonoUsedSize() / (1024 * 1024)
+ ";mhs;" + Profiler.GetMonoHeapSize() / (1024 * 1024)
);
var start = Time.realtimeSinceStartup;
*/
try
{
var root = PrefabObject.transform;
if (RendererArray != null)
{
//Debug.Log("RenderCount:" + RendererArray.Length);
for (int i = 0; i < RendererArray.Length; i++)
{
var rai = RendererArray[i];
if (rai != null )
{
var renderTrans = root;
if (!string.IsNullOrEmpty(rai.Path))
{
renderTrans = root.Find(rai.Path);
}
if (renderTrans != null)
{
rai.ToRenderer(renderTrans);
}
//rai.ToRenderer(rai.TheTransform);
}
}
}
if (AnimArray != null)
{
//Debug.Log("AnimationCount:" + AnimArray.Length);
for (int i = 0; i < AnimArray.Length; i++)
{
var anim = AnimArray[i];
if (anim != null)
{
var animTrans = root;
if (!string.IsNullOrEmpty(anim.Path))
{
animTrans = root.Find(anim.Path);
}
if (animTrans != null)
{
anim.ToAnimation(animTrans);
}
}
}
}
if (AnimtorArray != null)
{
//Debug.Log("AnimationCount:" + AnimArray.Length);
for (int i = 0; i < AnimtorArray.Length; i++)
{
var anim = AnimtorArray[i];
if (anim != null)
{
var animTrans = root;
if (!string.IsNullOrEmpty(anim.Path))
{
animTrans = root.Find(anim.Path);
}
if (animTrans != null)
{
anim.ToAnimator(animTrans);
}
}
}
}
if(TimelineArray != null)
{
var length = TimelineArray.Length;
//Debug.Log("TimelineCount:" + length);
for (int i = 0; i < length; i++)
{
var timeline = TimelineArray[i];
if(timeline != null)
{
var animTrans = root;
if (!string.IsNullOrEmpty(timeline.Path))
{
animTrans = root.Find(timeline.Path);
}
if (animTrans != null)
{
timeline.ToPlayableDirector(animTrans);
}
}
}
}
//设置名字
PrefabObject.name = Name;
}
catch(System.Exception ex)
{
Debug.LogException(ex);
}
/*
var duration = (Time.realtimeSinceStartup - start) * 1000;
Debug.LogError("ToPrefabGo:" + Name + ";;;" + duration + ";;内存:"
+ Profiler.GetTotalAllocatedMemory() / (1024 * 1024)
+ ";trm;" + Profiler.GetTotalReservedMemory() / (1024 * 1024)
+ ";turm;" + Profiler.GetTotalUnusedReservedMemory() / (1024 * 1024)
+ ";mus;" + Profiler.GetMonoUsedSize() / (1024 * 1024)
+ ";mhs;" + Profiler.GetMonoHeapSize() / (1024 * 1024)
);*/
}
else
{
Debug.LogError("当前资源不是一个有效资源,清除:"+ Name);
Unload();
}
return PrefabObject;
}
#endregion
#region//编辑器时执行--打包之前数据准备用
#if UNITY_EDITOR
//从预制对象创建资源信息
public PrefabAssetData FromPrefabGo(GameObject prefabGo,bool isUseTexName, string texDir, string savePath, System.Action<AnimListScript, string, string> checkAnim)
{
var go = GameObject.Instantiate(prefabGo);
go.name = prefabGo.name;
try
{
//删除播放脚本
var playScripts = go.GetComponentsInChildren<AnimPlayScript>(true);
for (int i = 0; playScripts != null && i < playScripts.Length; ++i)
{
GameObject.DestroyImmediate(playScripts[i]);
}
//处理AnimListScript --先处理Animation的原因是,节点可能会改名,导致路径不对.
var anims = go.GetComponentsInChildren<AnimListScript>(true);
if ((anims == null || anims.Length <= 0) && savePath.Contains("Prefab"))
{
//添加一个脚本,用于存储插槽数据
go.RequireComponent<AnimListScript>();
anims = go.GetComponentsInChildren<AnimListScript>(true);
}
//删除动作资源目录,用以重新生成动作
var animPath = savePath.Substring(0, savePath.LastIndexOf("/"));
animPath = string.Format("{0}/{1}", animPath, go.name);
if (System.IO.Directory.Exists(animPath))
{
System.IO.Directory.Delete(animPath, true);
}
List<AnimationAssetData> animList = new List<AnimationAssetData>();
{
AnimationAssetData curAnim = new AnimationAssetData();
for (int i = 0; i < anims.Length; i++)
{
var animTrans = anims[i].transform;
var animator = animTrans.GetComponent<Animator>();
//这里把runtimeAnimatorContorller给去除掉,为后来的Animator检查做准备
//只要使用AnimListScript,就表明这个模型的动作播放使用Playable的方式处理
if (animator != null && animator.runtimeAnimatorController != null)
{
animator.runtimeAnimatorController = null;
}
if (checkAnim != null)
{
//检查动作,将动作进行优化后重新挂载
checkAnim(anims[i], go.name, savePath);
}
if (curAnim.FromAnimation(anims[i], true))
{
curAnim.Path = GetFindPath(go.transform, animTrans);
curAnim.TheTransform = animTrans;
//判断之前有没有这个路径名称
foreach (var a in animList)
{
if (a.TheTransform == curAnim.TheTransform)
break;
if (a.Path == curAnim.Path)
{//如果有的话,就重新命名,并把gameobject中的也重新命名
curAnim.Path = curAnim.Path + "[AAD" + i + "]";
animTrans.gameObject.name = animTrans.gameObject.name + "[AAD" + i + "]";
break;
}
}
//Debug.Log("AnimationFindPath:" + curAnim.Path);
animList.Add(curAnim);
curAnim = new AnimationAssetData();
}
}
}
//Animator --先处理Animation的原因是,节点可能会改名,导致路径不对.
var animtors = go.GetComponentsInChildren<Animator>(true);
List<AnimatorAssetData> animorList = new List<AnimatorAssetData>();
{
AnimatorAssetData curAnim = new AnimatorAssetData();
for (int i = 0; i < animtors.Length; i++)
{
var animTrans = animtors[i].transform;
if (animtors[i].runtimeAnimatorController != null)
{
if (curAnim.FromAnimator(animtors[i]))
{
curAnim.Path = GetFindPath(go.transform, animTrans);
curAnim.TheTransform = animTrans;
//判断之前有没有这个路径名称
foreach (var a in animorList)
{
if (a.TheTransform == curAnim.TheTransform)
break;
if (a.Path == curAnim.Path)
{//如果有的话,就重新命名,并把gameobject中的也重新命名
curAnim.Path = curAnim.Path + "[AAD" + i + "]";
animTrans.gameObject.name = animTrans.gameObject.name + "[AAD" + i + "]";
break;
}
}
Debug.Log("AnimatorFindPath:" + curAnim.Path);
animorList.Add(curAnim);
curAnim = new AnimatorAssetData();
}
}
}
}
//处理Renderer
var renders = go.GetComponentsInChildren<Renderer>(true);
List<RenderAssetData> renderList = new List<RenderAssetData>();
{
RenderAssetData curRender = new RenderAssetData();
for (int i = 0; i < renders.Length; i++)
{
if (curRender.FromRenderer(renders[i], true, isUseTexName, texDir))
{
curRender.Path = GetFindPath(go.transform, renders[i].transform);
curRender.TheTransform = renders[i].transform;
//判断之前有没有这个路径名称
foreach (var r in renderList)
{
if (r.TheTransform == curRender.TheTransform)
break;
if (r.Path == curRender.Path)
{//如果有的话,就重新命名,并把gameobject中的也重新命名
curRender.Path = curRender.Path + "[PAD" + i + "]";
renders[i].gameObject.name = renders[i].gameObject.name + "[PAD" + i + "]";
break;
}
}
//Debug.Log("RenderFindPath:" + curRender.Path);
renderList.Add(curRender);
curRender = new RenderAssetData();
}
}
}
//处理Timeline
var playableDirectors = go.GetComponentsInChildren<PlayableDirector>(true);
List<TimelineAssetData> timelineAssetDataList = new List<TimelineAssetData>();
HashSet<string> timelinePaths = new HashSet<string>();
{
TimelineAssetData curTimeline = new TimelineAssetData();
for (int i = 0; i < playableDirectors.Length; i++)
{
if (curTimeline.FromPlayableDirector(playableDirectors[i]))
{
var path = GetFindPath(go.transform, playableDirectors[i].transform);
if (timelinePaths.Contains(path))
{
path = path + "[AAD" + i + "]";
playableDirectors[i].gameObject.name = path;
}
timelinePaths.Add(path);
curTimeline.Path = path;
//Debug.Log("TimelinePathFindPath:" + path);
timelineAssetDataList.Add(curTimeline);
curTimeline = new TimelineAssetData();
}
}
}
//处理粒子特效,隐藏会报错的粒子
var particles = go.GetComponentsInChildren<ParticleSystem>(true);
for (int i = 0; i < particles.Length; ++i)
{
if (particles[i].shape.enabled && particles[i].shape.shapeType == ParticleSystemShapeType.Mesh && particles[i].shape.mesh == null)
{
//隐藏报错粒子
particles[i].gameObject.SetActive(false);
}
}
//赋值
AnimtorArray = animorList.ToArray();
AnimArray = animList.ToArray();
RendererArray = renderList.ToArray();
TimelineArray = timelineAssetDataList.ToArray();
Name = go.name;
//需要先把go保存成预制
string saveAssetPath = savePath;
//var prefabGoIns = UnityEditor.PrefabUtility.InstantiatePrefab(prefabGo) as GameObject;
if(UnityEditor.PrefabUtility.SaveAsPrefabAsset(go, saveAssetPath) == null)
{
//保存失败,抛出异常
throw new System.Exception(string.Format("保存Prefab预制失败 go = {0}", go.name));
}
UnityEditor.AssetDatabase.ImportAsset(saveAssetPath);
DestroyImmediate(go);
PrefabObject = UnityEditor.AssetDatabase.LoadAssetAtPath(saveAssetPath, typeof(GameObject)) as GameObject;
}
catch(System.Exception ex)
{
DestroyImmediate(go);
throw ex;
}
return this;
}
//获取查找路径
private string GetFindPath(Transform root, Transform curr)
{
string result = string.Empty;
List<string> nameList = new List<string>();
while (curr != null && curr != root)
{
nameList.Add(curr.name);
curr = curr.parent;
}
if (nameList.Count > 0)
{
nameList.Reverse();
for (int i = 0; i < nameList.Count; i++)
{
result += "/" + nameList[i];
}
result = result.Substring(1);
}
return result;
}
#endif
#endregion
}
}