2025-09-17 16:40:02 -07:00

192 lines
6.0 KiB
C#

using AssetRipper.AssemblyDumper.Utils;
namespace AssetRipper.AssemblyDumper.Passes;
/// <summary>
/// This pass deliberately modifies the type tree for TextureImporter to reflect its yaml output.
/// It also changes the base class of VideoClipImporter to AssetImporter.
/// </summary>
internal static class Pass003_FixTextureImporterNodes
{
private const string MipMapsTypeName = "TextureImporterMipMapSettings"; //Fabricated
private const string MipMapsName = "m_MipMaps"; //Fabricated
private const string MipMapsOriginalName = "mipmaps";
private const string MipMapsStartFieldName = "m_MipMapMode";
private const string MipMapsEndFieldName = "m_MipMapFadeDistanceEnd";
private const string BumpMapTypeName = "TextureImporterBumpMapSettings"; //Fabricated
private const string BumpMapName = "m_BumpMap"; //Fabricated
private const string BumpMapOriginalName = "bumpmap";
private const string BumpMapStartFieldName = "m_ConvertToNormalMap";
private const string BumpMapEndFieldName = "m_NormalMapFilter";
private const string BumpMapEndFieldName2 = "m_FlipGreenChannel";//Introduced in 2022.1.0
private const int TextureImporterTypeId = 1006;
private const int TextureId = 27;
private const string ImageTextureName = "ImageTexture";
private const int ImageTextureId = 189;//This is currently unused and is close to Texture2DArray (187) and CubemapArray (188)
public static void DoPass()
{
foreach (UniversalClass? universalClass in SharedState.Instance.ClassInformation[TextureImporterTypeId].Values)
{
if (universalClass is not null)
{
DoPassOnClass(universalClass);
}
}
//ImageTexture is a fabricated class that represents a texture with pixel data.
CreateArtificialDerivedClass(ImageTextureName, ImageTextureId, TextureId);
//VideoClipImporter
ChangeBaseClass(1127, "AssetImporter");
//EditorSettings
ChangeBaseClass(159, "GlobalGameManager");
//EditorBuildSettings
ChangeBaseClass(1045, "GlobalGameManager");
//Texture2D
ChangeBaseClass(28, ImageTextureName);
//Texture3D
ChangeBaseClass(117, ImageTextureName);
//Texture2DArray
ChangeBaseClass(187, ImageTextureName);
//CubemapArray
ChangeBaseClass(188, ImageTextureName);
}
private static void ChangeBaseClass(int classId, string baseClass)
{
foreach (UniversalClass? universalClass in SharedState.Instance.ClassInformation[classId].Values)
{
if (universalClass is not null)
{
universalClass.BaseString = baseClass;
}
}
}
private static void CreateArtificialDerivedClass(string className, int classId, int baseClassId)
{
VersionedList<UniversalClass> list = new();
foreach ((UnityVersion version, UniversalClass? rendererClass) in SharedState.Instance.ClassInformation[baseClassId])
{
if (rendererClass is null)
{
list.Add(version, null);
}
else
{
UniversalClass duplicate = rendererClass.DeepClone();
duplicate.Name = className;
duplicate.OriginalName = className;
duplicate.TypeID = classId;
duplicate.OriginalTypeID = classId;
duplicate.IsAbstract = true;
duplicate.BaseString = rendererClass.Name;
if (duplicate.ReleaseRootNode is not null)
{
duplicate.ReleaseRootNode.TypeName = className;
}
if (duplicate.EditorRootNode is not null)
{
duplicate.EditorRootNode.TypeName = className;
}
list.Add(version, duplicate);
}
}
SharedState.Instance.ClassInformation.Add(classId, list);
}
private static void DoPassOnClass(UniversalClass universalClass)
{
universalClass.ReleaseRootNode?.DoPassOnRootNode();
universalClass.EditorRootNode?.DoPassOnRootNode();
}
private static void DoPassOnRootNode(this UniversalNode rootNode)
{
int mipMapsStartIndex = rootNode.GetSubnodeIndex(MipMapsStartFieldName);
int mipMapsEndIndex = rootNode.GetSubnodeIndex(MipMapsEndFieldName);
if (mipMapsStartIndex >= mipMapsEndIndex)
{
throw new Exception("MipMaps start later than its end");
}
int bumpMapStartIndex = rootNode.GetSubnodeIndex(BumpMapStartFieldName);
int bumpMapEndIndex = Math.Max(rootNode.GetSubnodeIndex(BumpMapEndFieldName), rootNode.TryGetSubnodeIndex(BumpMapEndFieldName2));
if (bumpMapStartIndex <= mipMapsEndIndex)
{
throw new Exception("BumpMap start later than MipMaps end");
}
if (bumpMapStartIndex >= bumpMapEndIndex)
{
throw new Exception("BumpMap start later than its end");
}
UniversalNode mipMapsNode = new();
mipMapsNode.Name = MipMapsName;
mipMapsNode.OriginalName = MipMapsOriginalName;
mipMapsNode.TypeName = MipMapsTypeName;
mipMapsNode.Version = 1;
mipMapsNode.MetaFlag = default;
for (int i = mipMapsStartIndex; i <= mipMapsEndIndex; i++)
{
mipMapsNode.SubNodes.Add(rootNode.SubNodes[i]);
}
UniversalNode bumpMapNode = new();
bumpMapNode.Name = BumpMapName;
bumpMapNode.OriginalName = BumpMapOriginalName;
bumpMapNode.TypeName = BumpMapTypeName;
bumpMapNode.Version = 1;
bumpMapNode.MetaFlag = default;
for (int i = bumpMapStartIndex; i <= bumpMapEndIndex; i++)
{
bumpMapNode.SubNodes.Add(rootNode.SubNodes[i]);
}
int count = rootNode.SubNodes.Count - (bumpMapEndIndex - bumpMapStartIndex) - (mipMapsEndIndex - mipMapsStartIndex);
List<UniversalNode> newSubnodes = new List<UniversalNode>(count);
for (int i = 0; i < mipMapsStartIndex; i++)
{
newSubnodes.Add(rootNode.SubNodes[i]);
}
newSubnodes.Add(mipMapsNode);
for (int i = mipMapsEndIndex + 1; i < bumpMapStartIndex; i++)
{
newSubnodes.Add(rootNode.SubNodes[i]);
}
newSubnodes.Add(bumpMapNode);
for (int i = bumpMapEndIndex + 1; i < rootNode.SubNodes.Count; i++)
{
newSubnodes.Add(rootNode.SubNodes[i]);
}
rootNode.SubNodes = newSubnodes;
}
private static int GetSubnodeIndex(this UniversalNode parent, string subnodeName)
{
int result = parent.SubNodes.FindIndex(n => n.Name == subnodeName);
return result >= 0 ? result : throw new Exception($"{subnodeName} not found");
}
private static int TryGetSubnodeIndex(this UniversalNode parent, string subnodeName)
{
return parent.SubNodes.FindIndex(n => n.Name == subnodeName);
}
}