WuhuIslandTesting/Library/PackageCache/com.unity.scriptablebuildpipeline@1.21.5/Editor/Utilities/LinkXMLGenerator.cs
2025-01-07 02:06:59 +01:00

272 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Linq;
using System.Text;
namespace UnityEditor.Build.Pipeline.Utilities
{
/// <summary>
/// This can be used to create a LinkXml for your build. This will ensure that the desired runtime types are packed into the build.
/// </summary>
public class LinkXmlGenerator
{
Dictionary<Type, Type> m_TypeConversion = new Dictionary<Type, Type>();
HashSet<Type> m_Types = new HashSet<Type>();
HashSet<Assembly> m_Assemblies = new HashSet<Assembly>();
/// <summary>
/// Obsolete, no longer does anything.
/// </summary>
[Obsolete] protected Dictionary<string, HashSet<string>> serializedClassesPerAssembly = null;
Dictionary<string, HashSet<string>> m_SerializedClassesPerAssembly = new Dictionary<string, HashSet<string>>();
/// <summary>
/// Constructs and returns a LinkXmlGenerator object that contains default UnityEditor to UnityEngine type conversions.
/// </summary>
/// <returns>LinkXmlGenerator object with the default UnityEngine type conversions.</returns>
public static LinkXmlGenerator CreateDefault()
{
var linker = new LinkXmlGenerator();
var types = GetEditorTypeConversions();
foreach (var pair in types)
linker.SetTypeConversion(pair.Key, pair.Value);
return linker;
}
/// <summary>
/// Returns the set of UnityEditor types that have valid runtime direct mappings.
/// </summary>
/// <returns>Array of KeyValuePairs containing the editor type and it's equivalent runtime type.</returns>
public static KeyValuePair<Type, Type>[] GetEditorTypeConversions()
{
var editor = Assembly.GetAssembly(typeof(UnityEditor.BuildPipeline));
return new[]
{
new KeyValuePair<Type, Type>(typeof(UnityEditor.Animations.AnimatorController), typeof(UnityEngine.RuntimeAnimatorController)),
new KeyValuePair<Type, Type>(editor.GetType("UnityEditor.Audio.AudioMixerController"), typeof(UnityEngine.Audio.AudioMixer)),
new KeyValuePair<Type, Type>(editor.GetType("UnityEditor.Audio.AudioMixerGroupController"), typeof(UnityEngine.Audio.AudioMixerGroup)),
new KeyValuePair<Type, Type>(typeof(UnityEditor.MonoScript), typeof(UnityEngine.Object)),
};
}
/// <summary>
/// Add runtime assembly to the LinkXml Generator.
/// </summary>
/// <param name="assemblies">The desired runtime assemblies.</param>
public void AddAssemblies(params Assembly[] assemblies)
{
if (assemblies == null)
return;
foreach (var a in assemblies)
AddAssemblyInternal(a);
}
/// <summary>
/// Add runtime assembly to the LinkXml Generator.
/// </summary>
/// <param name="assemblies">The desired runtime assemblies.</param>
public void AddAssemblies(IEnumerable<Assembly> assemblies)
{
if (assemblies == null)
return;
foreach (var a in assemblies)
AddAssemblyInternal(a);
}
/// <summary>
/// Add runtime type to the LinkXml Generator.
/// </summary>
/// <param name="types">The desired runtime types.</param>
public void AddTypes(params Type[] types)
{
if (types == null)
return;
foreach (var t in types)
AddTypeInternal(t);
}
/// <summary>
/// Add runtime type to the LinkXml Generator.
/// </summary>
/// <param name="types">The desired runtime types.</param>
public void AddTypes(IEnumerable<Type> types)
{
if (types == null)
return;
foreach (var t in types)
AddTypeInternal(t);
}
/// <summary>
/// Add SerializedReference class type from fully qualified name to the Generator, those will end up in PreservedTypes.xml
/// </summary>
/// <param name="serializedRefTypes">The SerializeReference instance fully qualified name we want to preserve.</param>
public void AddSerializedClass(IEnumerable<string> serializedRefTypes)
{
if (serializedRefTypes == null)
return;
foreach (var t in serializedRefTypes)
{
var indexOfAssembly = t.IndexOf(':');
if (indexOfAssembly != -1)
AddSerializedClassInternal(t.Substring(0, indexOfAssembly), t.Substring(indexOfAssembly + 1, t.Length - (indexOfAssembly + 1)));
}
}
private void AddTypeInternal(Type t)
{
if (t == null)
return;
Type convertedType;
if (m_TypeConversion.TryGetValue(t, out convertedType))
m_Types.Add(convertedType);
else
m_Types.Add(t);
}
private void AddSerializedClassInternal(string assemblyName, string classWithNameSpace)
{
if (string.IsNullOrEmpty(assemblyName))
return;
if (string.IsNullOrEmpty(classWithNameSpace))
return;
if (!m_SerializedClassesPerAssembly.TryGetValue(assemblyName, out HashSet<string> types))
m_SerializedClassesPerAssembly[assemblyName] = types = new HashSet<string>();
types.Add(classWithNameSpace);
}
private void AddAssemblyInternal(Assembly a)
{
if (a == null)
return;
m_Assemblies.Add(a);
}
/// <summary>
/// Setup runtime type conversion
/// </summary>
/// <param name="a">Convert from type.</param>
/// <param name="b">Convert to type.</param>
public void SetTypeConversion(Type a, Type b)
{
m_TypeConversion[a] = b;
}
/// <summary>
/// Save the LinkXml to the specified path.
/// </summary>
/// <param name="path">The path to save the linker xml file.</param>
public void Save(string path)
{
var assemblyMap = new Dictionary<Assembly, List<Type>>();
foreach (var a in m_Assemblies)
{
if (!assemblyMap.TryGetValue(a, out _))
assemblyMap.Add(a, new List<Type>());
}
foreach (var t in m_Types)
{
var a = t.Assembly;
List<Type> types;
if (!assemblyMap.TryGetValue(a, out types))
assemblyMap.Add(a, types = new List<Type>());
types.Add(t);
}
XmlDocument doc = new XmlDocument();
var linker = doc.AppendChild(doc.CreateElement("linker"));
foreach (var k in assemblyMap.OrderBy(a => a.Key.FullName))
{
var assembly = linker.AppendChild(doc.CreateElement("assembly"));
var attr = doc.CreateAttribute("fullname");
attr.Value = k.Key.FullName;
if (assembly.Attributes != null)
{
assembly.Attributes.Append(attr);
if (m_Assemblies.Contains(k.Key))
{
var preserveAssembly = doc.CreateAttribute("preserve");
preserveAssembly.Value = "all";
assembly.Attributes.Append(preserveAssembly);
}
foreach (var t in k.Value.OrderBy(t => t.FullName))
{
var typeEl = assembly.AppendChild(doc.CreateElement("type"));
var tattr = doc.CreateAttribute("fullname");
tattr.Value = t.FullName;
if (typeEl.Attributes != null)
{
typeEl.Attributes.Append(tattr);
var pattr = doc.CreateAttribute("preserve");
pattr.Value = "all";
typeEl.Attributes.Append(pattr);
}
}
//Add serialize reference classes which are contained in the current assembly
var assemblyName = k.Key.GetName().Name;
if (m_SerializedClassesPerAssembly.ContainsKey(assemblyName))
{
//Add content for this
foreach (var t in m_SerializedClassesPerAssembly[assemblyName])
{
var typeEl = assembly.AppendChild(doc.CreateElement("type"));
var tattr = doc.CreateAttribute("fullname");
tattr.Value = t;
if (typeEl.Attributes != null)
{
typeEl.Attributes.Append(tattr);
var pattr = doc.CreateAttribute("preserve");
pattr.Value = "nothing";
typeEl.Attributes.Append(pattr);
var sattr = doc.CreateAttribute("serialized");
sattr.Value = "true";
typeEl.Attributes.Append(sattr);
}
}
m_SerializedClassesPerAssembly.Remove(assemblyName);
}
}
}
//Add serialize reference classes which are contained in other assemblies not yet removed.
foreach (var k in m_SerializedClassesPerAssembly.OrderBy(a => a.Key))
{
var assembly = linker.AppendChild(doc.CreateElement("assembly"));
var attr = doc.CreateAttribute("fullname");
attr.Value = k.Key;
if (assembly.Attributes != null)
{
assembly.Attributes.Append(attr);
//Add content for this
foreach (var t in k.Value.OrderBy(t => t))
{
var typeEl = assembly.AppendChild(doc.CreateElement("type"));
var tattr = doc.CreateAttribute("fullname");
tattr.Value = t;
if (typeEl.Attributes != null)
{
typeEl.Attributes.Append(tattr);
var pattr = doc.CreateAttribute("preserve");
pattr.Value = "nothing";
typeEl.Attributes.Append(pattr);
var sattr = doc.CreateAttribute("serialized");
sattr.Value = "true";
typeEl.Attributes.Append(sattr);
}
}
}
}
doc.Save(path);
}
}
}