using AssetRipper.AssemblyDumper.Utils; namespace AssetRipper.AssemblyDumper.Passes; /// /// This pass deliberately modifies the type tree for TextureImporter to reflect its yaml output. /// It also changes the base class of VideoClipImporter to AssetImporter. /// 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 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 newSubnodes = new List(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); } }