/// <summary> /// Load top level manifests to track dependencies /// </summary> public static void LoadManifests(bool makedep = true) { foreach (var man in Directory.GetFiles(Dir.abdata, "*.*", SearchOption.TopDirectoryOnly)) { var ab = AssetBundle.LoadFromFile(man); var fn = man.Substring(Dir.abdata.Length); if (ab == null) { continue; } Debug.Log("scanning for manifest in ", man); var mf = ab.LoadAsset <AssetBundleManifest>("AssetBundleManifest"); if (mf != null) { AssetBundleManager.ManifestBundlePack["abdata/" + fn] = new AssetBundleManager.BundlePack() { AssetBundleManifest = mf }; if (makedep) { foreach (var sab in mf.GetAllAssetBundles()) { var rpath = sab.Replace("abdata/", ""); if (!File.Exists(Dir.abdata + rpath)) { Debug.Error("Nonexistent ", rpath, " announced in manifest ", man); continue; } var abi = LoadedAssetBundle.Make(rpath); abi.hasManifest = true; abi.hasRealManifest = true; foreach (var tdep in mf.GetAllDependencies(sab)) { Debug.Log(" =>", sab, " depends on ", tdep); string dep = tdep.Replace("abdata/", ""); if (!abi.deps.Contains(dep)) { abi.deps.Add(dep); } } } } } ab.Unload(false); } }
/// <summary> /// Rescan the directory mappings /// </summary> public static void Rescan(bool flush = true) { Debug.Log("VFS: Rescan"); string abdata = "abdata/"; string inabdata = Dir.root + abdata; if (flush) { dc.abs.Clear(); LoadManifests(); } dc.dirLists.Clear(); // initially map everything to self Debug.Log("unity3d"); foreach (var bundle in Directory.GetFiles(inabdata, "*.unity3d", SearchOption.AllDirectories)) { var rel = bundle.Replace("\\", "/"); var name = rel.Substring(Dir.abdata.Length); if (!settings.withoutManifest && !name.ToLower().StartsWith("sound/") && (!dc.abs.TryGetValue(name, out LoadedAssetBundle mab) || !mab.hasManifest)) { Debug.Info("Skipping mod ", rel, " as it is not in any manifest and mod loading from abdata is not enabled."); continue; } LoadedAssetBundle.Make(name, rel.Substring(Dir.root.Length)); } Debug.Log("dirlists"); Dictionary <string, bool> lhash = new Dictionary <string, bool>(); // Now scan for listable bundles in abdata foreach (var ld in listable) { var lld = ld.Replace("!", ""); lhash[lld] = lld != ld; if (!Directory.Exists(Dir.abdata + lld)) { continue; } dc.dirLists[lld] = new List <string>(); foreach (var blist in Directory.GetFiles(Dir.abdata + lld, "*.unity3d", ld != lld ? SearchOption.TopDirectoryOnly : SearchOption.AllDirectories)) { var fn = blist.Replace("\\", "/").Substring(Dir.abdata.Length); Debug.Log("processing", fn); // no manifest; skip it if (!settings.withoutManifest && !fn.ToLower().StartsWith("sound/") && (!dc.abs.TryGetValue(fn, out LoadedAssetBundle mab) || !mab.hasManifest)) { Debug.Info("Skipping mod ", fn, " as it is not in any manifest and mod loading from abdata is not enabled."); continue; } Debug.Log("added to dirlist"); dc.dirLists[lld].Add(fn); // if recursive, walk up and populate dirlists int idx = fn.LastIndexOf('/'); if (ld == lld && idx >= 0) { string td = fn.Remove(idx); while (td != lld) { if (!dc.dirLists.TryGetValue(td, out List <string> tdl)) { tdl = dc.dirLists[td] = new List <string>(); } tdl.Add(fn); td = td.Remove(td.LastIndexOf('/')); } } } } Debug.Log("mods"); // now scan mods, those will simply override the tables above if (settings.loadMods) { foreach (var mod in Directory.GetDirectories(Dir.mod, "*.*", SearchOption.TopDirectoryOnly)) { Debug.Log("Processing ", mod); var inmod = mod + "/"; foreach (var tmpfn in Directory.GetFiles(inmod, "*.*", SearchOption.AllDirectories)) { var currentfn = tmpfn.Replace("\\", "/"); var realFn = currentfn.Substring(Dir.root.Length); // real path relative to root var fn = currentfn.Substring(inmod.Length); // virtualpath if (fn.ToLower().StartsWith("abdata/")) { fn = fn.Substring(7); } // may override original abdata mapping if (fn.EndsWith(".unity3d")) { LoadedAssetBundle.Make(fn, realFn); } // keep stripping last path component of the file path until we match // a path which is listable var ofn = fn; int ind; int stripped = 0; while ((ind = fn.LastIndexOf('/')) >= 0) { fn = fn.Remove(ind); // is directory now // Debug.Log("listable lookup", fn, ofn); var virtab = ofn.Remove(ofn.LastIndexOf('/')) + ".unity3d"; // a file inside listable folder was detected, we'll need to inspect the folder if (lhash.TryGetValue(fn, out bool norecurse)) { // an actual bundle, insert it as-is if (ofn.EndsWith(".unity3d")) { if ((!norecurse || stripped == 0) && !dc.dirLists[fn].Contains(ofn)) { dc.dirLists[fn].Add(ofn.Replace("+", "")); } } else { // a file in a directory. the directory itself then becomes a virtual bundle // if there is no accompanying real one // add to dir listings if ((!norecurse || stripped == 0) || !dc.dirLists[fn].Contains(virtab)) { dc.dirLists[fn].Add(virtab); } } } if (fn != "" && stripped == 0 && !ofn.EndsWith("*.unity3d")) { // create a virtual bundle var assname = RemoveExt(Path.GetFileName(ofn)); var vab = LoadedAssetBundle.Make(virtab); vab.hasManifest = true; Debug.Log("adding virtual asset ", assname, "into", virtab); vab.virtualAssets[assname.ToLower()] = realFn; var nvpath = realFn.Remove(realFn.LastIndexOf('/')); Debug.Log(assname, virtab, fn, nvpath, vab.realPath); if (vab.realPath == null && nvpath != vab.realPath) { vab.realPath = nvpath; } else { Debug.Log("Not overriding ", vab.realPath, " with ", nvpath); } } stripped++; } } } } }