diff --git a/Source/1.6/AMRetextureSupport/RetextureUtility.cs b/Source/1.6/AMRetextureSupport/RetextureUtility.cs index 5713de3..43e1e9e 100644 --- a/Source/1.6/AMRetextureSupport/RetextureUtility.cs +++ b/Source/1.6/AMRetextureSupport/RetextureUtility.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using JetBrains.Annotations; using UnityEngine; using Verse; using LudeonTK; @@ -195,18 +196,26 @@ public static IEnumerable GetModWeaponReports(ModContentPac private static IEnumerable<(ModContentPack mod, Texture2D texture)> ScanAssetBundles(string texPath) { var mods = LoadedModManager.RunningModsListForReading; - string path = Path.Combine("Assets", "Data"); + string baseBundlePath = Path.Combine("Assets", "Data"); for (int i = mods.Count - 1; i >= 0; i--) { - string path2 = Path.Combine(path, mods[i].FolderName); - foreach (AssetBundle assetBundle in mods[i].assetBundles.loadedAssetBundles) + var mod = mods[i]; + + string dirForBundleWithFolderName = Path.Combine(baseBundlePath, mod.FolderName); + string dirForBundleWithPackageId = Path.Combine(baseBundlePath, mod.PackageIdPlayerFacing); + string path1 = Path.Combine(Path.Combine(dirForBundleWithFolderName, GenFilePaths.ContentPath()), texPath).ToLowerInvariant(); + string path2 = Path.Combine(Path.Combine(dirForBundleWithPackageId, GenFilePaths.ContentPath()), texPath).ToLowerInvariant(); + + foreach (AssetBundle bundle in mod.assetBundles.loadedAssetBundles) { - string str = Path.Combine(Path.Combine(path2, GenFilePaths.ContentPath()), texPath); - foreach (string ext in ModAssetBundlesHandler.TextureExtensions) { - var loaded = assetBundle.LoadAsset(str + ext); + var loaded = bundle.LoadAsset(path1 + ext); + if (loaded != null) + yield return (mods[i], loaded); + + loaded = bundle.LoadAsset(path2 + ext); if (loaded != null) yield return (mods[i], loaded); } @@ -221,19 +230,93 @@ public static IEnumerable GetModWeaponReports(ModContentPac { var mod = mods[i]; + // Textures from the textures folder. var textures = mod.textures?.contentList; - if (textures == null) - continue; - - foreach (var pair in textures) + if (textures != null) + { + foreach ((string path, Texture2D texture) in textures) + { + yield return (mod, texture, path); + } + } + + // Textures from asset bundles. + foreach (var tuple in GetTexturesFromBundles(mod)) { - yield return (mod, pair.Value, pair.Key); + yield return tuple; } } + } + private static IEnumerable<(ModContentPack mod, Texture2D texture, string path)> GetTexturesFromBundles(ModContentPack mod) + { + // Ignore core mods, they don't use asset bundles for the main textures and would cause unnecessary performance overhead. + if (mod.IsCoreMod || mod.IsOfficialMod) + yield break; + + if (mod.assetBundles == null || mod.assetBundles.loadedAssetBundles.Count == 0) + yield break; + + string[] validExtensions = ModAssetBundlesHandler.TextureExtensions; + + string modsDir = Path.Combine("Assets", "Data"); + string dirForBundleWithFolderName = Path.Combine(modsDir, mod.FolderName); + string dirForBundleWithPackageId = Path.Combine(modsDir, mod.PackageIdPlayerFacing); + + const string FOLDER_PATH = ""; // Want to get all textures in the root Textures/ folder. + string pathWithoutExtWithModName = Path.Combine(Path.Combine(dirForBundleWithFolderName, GenFilePaths.ContentPath()).Replace('\\', '/'), FOLDER_PATH).ToLower(); + string pathWithoutExtWithPackageId = Path.Combine(Path.Combine(dirForBundleWithPackageId, GenFilePaths.ContentPath()).Replace('\\', '/'), FOLDER_PATH).ToLower(); + string text2 = pathWithoutExtWithModName; + if (text2[^1] != '/') + pathWithoutExtWithModName += '/'; + + string text3 = pathWithoutExtWithPackageId; + if (text3[^1] != '/') + pathWithoutExtWithPackageId += '/'; + + int bundleCount = mod.assetBundles.loadedAssetBundles.Count; + for (int i = 0; i < bundleCount; i++) + { + var bundle = mod.assetBundles.loadedAssetBundles[i]; + var namesTrie = mod.AllAssetNamesInBundleTrie(i); + + // Gets names of files inside the Textures/ folder inside the bundle. + var paths1 = namesTrie.GetByPrefix(pathWithoutExtWithModName); + var paths2 = namesTrie.GetByPrefix(pathWithoutExtWithPackageId); + + foreach (string texPath in paths1.Concat(paths2)) + { + // Ignore files that are not textures. + string ext = Path.GetExtension(texPath); + if (!validExtensions.Contains(ext)) + continue; + + var loadedTexture = bundle.LoadAsset(texPath); + if (loadedTexture == null) + { + Log.Warning($"[MA] Failed to load texture '{texPath}' from asset bundle '{bundle.name}' ({i}) in mod '{mod.Name}' ({mod.PackageId})"); + continue; + } + + string relativePath = texPath.Replace(pathWithoutExtWithModName, "").Replace(pathWithoutExtWithPackageId, ""); + + // Remove leading slash. + if (relativePath.StartsWith("/")) + relativePath = relativePath[1..]; + + // Remove extension. + relativePath = relativePath[..relativePath.LastIndexOf('.')]; + + // Normalize slashes. + relativePath = relativePath.Replace('\\', '/'); + + yield return (mod, loadedTexture, relativePath); + } + } + } - [DebugOutput("Melee Animation")] + [DebugOutput("Melee Animation"), UsedImplicitly] private static void LogAllTextureReports() { var meleeWeapons = DefDatabase.AllDefsListForReading.Where(d => IsMeleeWeapon(d)); @@ -292,7 +375,7 @@ private static string ResolveTexturePath(ThingDef weapon, int pass, out bool can if (textures == null) continue; - string prefix = (xmlPath[xmlPath.Length - 1] == '/') ? xmlPath : xmlPath + "/"; + string prefix = (xmlPath[^1] == '/') ? xmlPath : xmlPath + "/"; foreach (string path in textures.GetByPrefix(prefix).OrderBy(s => s)) { return path; diff --git a/Source/1.6/AnimationMod.sln.DotSettings b/Source/1.6/AnimationMod.sln.DotSettings index afa279d..090b1fe 100644 --- a/Source/1.6/AnimationMod.sln.DotSettings +++ b/Source/1.6/AnimationMod.sln.DotSettings @@ -1,5 +1,6 @@  CAI + MCP MPB <Policy><Descriptor Staticness="Any" AccessRightKinds="Any" Description="Types and namespaces"><ElementKinds><Kind Name="NAMESPACE" /><Kind Name="CLASS" /><Kind Name="STRUCT" /><Kind Name="ENUM" /><Kind Name="DELEGATE" /></ElementKinds></Descriptor><Policy Inspect="True" WarnAboutPrefixesAndSuffixes="False" Prefix="" Suffix="" Style="AaBb_AaBb" /></Policy> True