コード例 #1
0
        private static string FindFirstOfSplit(IAssetsFileProvider fp, string assetsFile)
        {
            int lastDot = assetsFile.LastIndexOf('.');

            if (lastDot > 0)
            {
                string afterDot = assetsFile.Substring(lastDot, assetsFile.Length - lastDot);
                string noSplit;
                if (afterDot.ToLower().StartsWith(".split"))
                {
                    noSplit = assetsFile.Substring(0, lastDot);
                    if (fp.FileExists(noSplit))
                    {
                        return(noSplit);
                    }
                }
                else
                {
                    noSplit = assetsFile;
                }
                var split0 = noSplit + ".split0";
                if (fp.FileExists(split0))
                {
                    return(split0);
                }
            }
            if (fp.FileExists(assetsFile))
            {
                return(assetsFile);
            }
            return(null);
        }
コード例 #2
0
ファイル: AssetsFile.cs プロジェクト: unusable/QuestomAssets
        public AssetsFile(AssetsManager manager, IAssetsFileProvider fileProvider, string assetsRootPath, string assetsFileName, bool loadData = true)
        {
            Manager        = manager;
            FileProvider   = fileProvider;
            AssetsRootPath = assetsRootPath;
            AssetsFilename = assetsFileName;

            OpenBaseStream();

            BaseStream.Seek(0, SeekOrigin.Begin);
            using (AssetsReader reader = new AssetsReader(BaseStream, false))
            {
                Header = new AssetsFileHeader(reader);
            }

            if (Header.MetadataSize > Header.FileSize || Header.ObjectDataOffset < Header.MetadataSize || Header.Version != 17)
            {
                throw new NotSupportedException($"{AssetsFilename} doesn't appear to be a valid assets file, or {Header.Version} is unsupported!");
            }

            if (loadData)
            {
                LoadData();
            }
        }
コード例 #3
0
ファイル: ApkSigner.cs プロジェクト: unusable/QuestomAssets
        /// <summary>
        /// Writes the MANIFEST.MF name and hash and the sigfile.SF hash for the sourceFile
        /// </summary>
        private void WriteEntryHashes(IAssetsFileProvider provider, string sourceFile, Stream manifestFileStream, Stream signatureFileStream)
        {
            using (Stream s = provider.GetReadStream(sourceFile))
            {
                var hash = _sha.ComputeHash(s);
                using (MemoryStream msSection = new MemoryStream())
                {
                    string hashOfMFSection = null;
                    using (StreamWriter swSection = GetSW(msSection))
                    {
                        swSection.WriteLine($"Name: {sourceFile}");
                        swSection.WriteLine($"SHA1-Digest: {Convert.ToBase64String(hash)}");
                        swSection.WriteLine("");
                    }
                    msSection.Seek(0, SeekOrigin.Begin);
                    hashOfMFSection = Convert.ToBase64String(_sha.ComputeHash(msSection));
                    msSection.Seek(0, SeekOrigin.Begin);
                    var actualString = UTF8Encoding.UTF8.GetString(msSection.ToArray());
                    using (var swSFFile = GetSW(signatureFileStream))
                    {
                        swSFFile.WriteLine($"Name: {sourceFile}");
                        swSFFile.WriteLine($"SHA1-Digest: {hashOfMFSection}");
                        swSFFile.WriteLine();
                    }

                    msSection.Seek(0, SeekOrigin.Begin);
                    msSection.CopyTo(manifestFileStream);
                }
            }
        }
コード例 #4
0
        public static Stream ReadCombinedAssets(this IAssetsFileProvider fp, string assetsFilePath)
        {
            string actualName = fp.CorrectAssetFilename(assetsFilePath);

            List <string> assetFiles = new List <string>();

            if (actualName.ToLower().EndsWith("split0"))
            {
                assetFiles.AddRange(fp.FindFiles(actualName.Replace(".split0", ".split*"))
                                    .OrderBy(x => Convert.ToInt32(x.Split(new string[] { ".split" }, StringSplitOptions.None).Last())));
            }
            else
            {
                return(fp.GetReadStream(actualName));
            }
            MemoryStream msFullFile = new MemoryStream();

            foreach (string assetsFile in assetFiles)
            {
                byte[] fileBytes = fp.Read(assetsFile);
                msFullFile.Write(fileBytes, 0, fileBytes.Length);
            }

            return(msFullFile);
        }
コード例 #5
0
 protected override QaeConfig GetQaeConfig(IAssetsFileProvider prov)
 {
     return(new QaeConfig()
     {
         AssetsPath = "assets/bin/Data/", SongsPath = "", FileProvider = prov, SongFileProvider = new FolderFileProvider(".\\", false)
     });
 }
コード例 #6
0
 public AssetsManager(IAssetsFileProvider fileProvider, string assetsRootPath, Dictionary <string, Type> classNameToTypes)
 {
     _fileProvider     = fileProvider;
     _assetsRootPath   = assetsRootPath;
     LazyLoad          = true;
     ClassNameToTypes  = classNameToTypes;
     ForceLoadAllFiles = false;
 }
コード例 #7
0
        public static bool Patch(IAssetsFileProvider apk, FilePatch patch)
        {
            string binaryFile = patch.Filename;

            if (!apk.FileExists(binaryFile))
            {
                Console.WriteLine("Binary file to patch doesn't exist in the APK!");
                return(false);
            }
            byte[] binaryBytes = apk.Read(binaryFile);
            if (binaryBytes.Length != patch.ExpectedFileSize)
            {
                Console.WriteLine("Binary file to patch is the wrong length!");
                return(false);
            }
            List <Patch> toApply = new List <Patch>();

            Console.WriteLine("Verifying patches binary...");
            using (MemoryStream msBinary = new MemoryStream(binaryBytes))
            {
                //verify each of the patches can be applied or already are applied
                foreach (Patch p in patch.Patches)
                {
                    msBinary.Seek(p.Address, SeekOrigin.Begin);
                    byte[] readVals = new byte[p.ExpectedData.Count];
                    msBinary.Read(readVals, 0, p.ExpectedData.Count);

                    if (!readVals.SequenceEqual(p.ExpectedData))
                    {
                        msBinary.Seek(p.Address, SeekOrigin.Begin);
                        readVals = new byte[p.PatchData.Count];
                        msBinary.Read(readVals, 0, p.PatchData.Count);
                        if (readVals.SequenceEqual(p.PatchData))
                        {
                            Console.WriteLine($"Patch {p.Name} already appears to be applied.");
                            continue;
                        }
                        else
                        {
                            Console.WriteLine($"Patch {p.Name} can't be applied to this binary, the code at the patch location doesn't match what was expected.  Aborting any patching...");
                            //if one patch can't be applied, abort the whole thing
                            return(false);
                        }
                    }
                }
                foreach (Patch p in toApply)
                {
                    msBinary.Seek(p.Address, SeekOrigin.Begin);
                    msBinary.Write(p.PatchData.ToArray(), 0, p.PatchData.Count);
                }
                msBinary.Seek(0, SeekOrigin.Begin);

                apk.Write(binaryFile, msBinary.ToArray(), true, true);
            }
            Console.WriteLine("Done patching binary!");
            return(true);
        }
コード例 #8
0
ファイル: AssetViewer.cs プロジェクト: Assistant/QuestStopgap
        private void CloseStuff()
        {
            etMain.DataSource  = null;
            etLeft.DataSource  = null;
            etRight.DataSource = null;
            cbAssetsFile.Items.Clear();

            if (_fileProvider != null)
            {
                _fileProvider.Dispose();
                _fileProvider = null;
            }
        }
コード例 #9
0
 public static void WriteCombinedAssets(this IAssetsFileProvider fp, AssetsFile assetsFile, string assetsFilePath)
 {
     if (assetsFilePath.EndsWith("split0"))
     {
         throw new ArgumentException("Don't pass in filenames with split0, pass in the original.");
     }
     fp.DeleteFiles(assetsFilePath + ".split*");
     using (var ms = new MemoryStream())
     {
         assetsFile.Write(ms);
         ms.Seek(0, SeekOrigin.Begin);
         fp.Write(assetsFilePath, ms.ToArray(), true, true);
     }
 }
コード例 #10
0
        public static string CorrectAssetFilename(this IAssetsFileProvider fp, string assetsFile)
        {
            var correctName = FindFirstOfSplit(fp, assetsFile);

            if (correctName != null)
            {
                return(correctName);
            }

            //some of the files in ExternalFiles have library/ on them, but they're actually in Resources/
            if (assetsFile.Contains("library/"))
            {
                string whyUnity = assetsFile.Replace("library/", "Resources/");
                correctName = FindFirstOfSplit(fp, whyUnity);
                if (correctName != null)
                {
                    return(correctName);
                }

                //whyUnity = assetsFile.Replace("library/", "");
                //correctName = FindFirstOfSplit(fp, whyUnity);
                //if (correctName != null)
                //    return correctName;

                //whyUnity = assetsFile.Replace("/library/", "");
                //correctName = FindFirstOfSplit(fp, whyUnity);
                //if (correctName != null)
                //    return correctName;
            }

            //some of the files in ExternalFiles have library/ on them, but they're actually in the root path
            var splitPath = assetsFile.Split('/').ToList();

            if (splitPath.Count() > 1)
            {
                splitPath.RemoveAt(splitPath.Count - 2);
                correctName = String.Join("/", splitPath);
                correctName = FindFirstOfSplit(fp, correctName);
                if (correctName != null)
                {
                    return(correctName);
                }
            }



            throw new ArgumentException($"The assets file {assetsFile} doesn't exist in with any known name variations!");
        }
コード例 #11
0
        public static string CorrectAssetFilename(this IAssetsFileProvider fp, string assetsFile)
        {
            var correctName = FindFirstOfSplit(fp, assetsFile);

            if (correctName != null)
            {
                return(correctName);
            }
            //some of the files in ExternalFiles have library/ on them, but they're actually in the root path
            var splitPath = assetsFile.Split('/').ToList();

            if (splitPath.Count() > 1)
            {
                splitPath.RemoveAt(splitPath.Count - 2);
                correctName = String.Join("/", splitPath);
                correctName = FindFirstOfSplit(fp, correctName);
                if (correctName != null)
                {
                    return(correctName);
                }
            }

            throw new ArgumentException("The file doesn't exist in the APK with any name!");
        }
コード例 #12
0
        public static Stream ReadCombinedAssets(this IAssetsFileProvider fp, string assetsFilePath, out bool wasCombined)
        {
            string actualName = fp.CorrectAssetFilename(assetsFilePath);

            List <string> assetFiles = new List <string>();

            if (actualName.ToLower().EndsWith("split0"))
            {
                assetFiles.AddRange(fp.FindFiles(actualName.Replace(".split0", ".split*"))
                                    .OrderBy(x => Convert.ToInt32(x.Split(new string[] { ".split" }, StringSplitOptions.None).Last())));
            }
            else
            {
                wasCombined = false;
                return(fp.GetReadStream(actualName));
            }
            wasCombined = true;
            //TODO: property or something on the file provider interface letting this code know if it should use the combined stream
            //      I think combined stream may perform horribly on zip files or cause other issues.

            if (true)
            {
                return(new CombinedStream(assetFiles, fp));
            }
            else
            {
                MemoryStream msFullFile = new MemoryStream();
                foreach (string assetsFile in assetFiles)
                {
                    byte[] fileBytes = fp.Read(assetsFile);
                    msFullFile.Write(fileBytes, 0, fileBytes.Length);
                }

                return(msFullFile);
            }
        }
コード例 #13
0
ファイル: AssetViewer.cs プロジェクト: Assistant/QuestStopgap
        private void BtnLoad_Click(object sender, EventArgs e)
        {
            ContextMenu cm = new ContextMenu(new MenuItem[]
            {
                new MenuItem("APK", (s, e2) =>
                {
                    OpenFileDialog ofd = new OpenFileDialog()
                    {
                        CheckFileExists = true,
                        Title           = "Open Bundle File",
                        Multiselect     = false
                    };
                    if (ofd.ShowDialog() == DialogResult.Cancel)
                    {
                        return;
                    }
                    CloseStuff();
                    try
                    {
                        _fileProvider = new ApkAssetsFileProvider(ofd.FileName, FileCacheMode.Memory, false);
                        _manager      = new AssetsManager(_fileProvider, BSConst.KnownFiles.AssetsRootPath, BSConst.GetAssetTypeMap());
                        if (_fileProvider.FindFiles("globalgamemanagers").Count > 0)
                        {
                            _manager.GetAssetsFile("globalgamemanagers.assets");
                        }
                        if (_fileProvider.FindFiles("globalgamemanagers.assets*").Count > 0)
                        {
                            _manager.GetAssetsFile("globalgamemanagers.assets");
                        }
                        _manager.FindAndLoadAllAssets();
                        FillAssetsFiles();
                        this.Text = "Assets Explorer - " + Path.GetFileName(ofd.FileName);
                    }
                    catch (Exception ex)
                    {
                        Log.LogErr("Couldn't load APK!", ex);
                        MessageBox.Show("Failed to load!");
                        if (_fileProvider != null)
                        {
                            _fileProvider.Dispose();
                            _fileProvider = null;
                        }
                        return;
                    }
                }),
                new MenuItem("Folder", (s, e2) =>
                {
                    FolderBrowserDialog fbd = new FolderBrowserDialog()
                    {
                        ShowNewFolderButton = false,
                        Description         = "Select Assets Root Folder"
                    };
                    if (fbd.ShowDialog() == DialogResult.Cancel)
                    {
                        return;
                    }
                    CloseStuff();
                    try
                    {
                        _fileProvider = new FolderFileProvider(fbd.SelectedPath, false);
                        _manager      = new AssetsManager(_fileProvider, "", BSConst.GetAssetTypeMap());
                        if (_fileProvider.FindFiles("globalgamemanagers").Count > 0)
                        {
                            _manager.GetAssetsFile("globalgamemanagers.assets");
                        }
                        if (_fileProvider.FindFiles("globalgamemanagers.assets*").Count > 0)
                        {
                            _manager.GetAssetsFile("globalgamemanagers.assets");
                        }
                        _manager.FindAndLoadAllAssets();
                        FillAssetsFiles();
                        this.Text = "Assets Explorer - " + Path.GetFileName(fbd.SelectedPath);
                    }
                    catch (Exception ex)
                    {
                        Log.LogErr("Couldn't load APK!", ex);
                        MessageBox.Show("Failed to load!");
                        if (_fileProvider != null)
                        {
                            _fileProvider.Dispose();
                            _fileProvider = null;
                        }
                        return;
                    }
                }),
                new MenuItem("Bundle", (s, e2) =>
                {
                    OpenFileDialog ofd = new OpenFileDialog()
                    {
                        CheckFileExists = true,
                        Title           = "Open Bundle File",
                        Multiselect     = false
                    };
                    if (ofd.ShowDialog() == DialogResult.Cancel)
                    {
                        return;
                    }
                    CloseStuff();
                    try
                    {
                        _fileProvider = new BundleFileProvider(ofd.FileName, true);
                        _manager      = new AssetsManager(_fileProvider, "", BSConst.GetAssetTypeMap());
                        _manager.FindAndLoadAllAssets();
                        FillAssetsFiles();
                        this.Text = "Assets Explorer - " + Path.GetFileName(ofd.FileName);
                    }
                    catch (Exception ex)
                    {
                        Log.LogErr("Couldn't load bundle!", ex);
                        MessageBox.Show("Failed to load!");
                        if (_fileProvider != null)
                        {
                            _fileProvider.Dispose();
                            _fileProvider = null;
                        }
                        return;
                    }
                })
            });

            cm.Show(btnLoad, new Point(0, btnLoad.Height));
            return;
        }
コード例 #14
0
ファイル: Extensions.cs プロジェクト: Assistant/QuestStopgap
        public static string ReadToString(this IAssetsFileProvider provider, string filename)
        {
            var data = provider.Read(filename);

            return(System.Text.Encoding.UTF8.GetString(data));
        }
コード例 #15
0
 public CombinedStream(List <string> orderedSplitFiles, IAssetsFileProvider provider)
 {
     _fileProvider = provider;
     InitFromFiles(orderedSplitFiles);
 }
コード例 #16
0
ファイル: ApkSigner.cs プロジェクト: unusable/QuestomAssets
        public void Sign(IAssetsFileProvider fileProvider)
        {
            MemoryStream msManifestFile = new MemoryStream();
            MemoryStream msSigFile      = new MemoryStream();

            byte[]       keyBlock;
            MemoryStream msSignatureFileBody = new MemoryStream();

            try
            {
                //create the MF file header
                using (StreamWriter swManifest = GetSW(msManifestFile))
                {
                    swManifest.WriteLine("Manifest-Version: 1.0");
                    swManifest.WriteLine("Created-By: emulamer");
                    swManifest.WriteLine();
                }

                //so that we can do it in one pass, write the MF and SF line items at the same time to their respective streams
                foreach (var infFile in fileProvider.FindFiles("*").Where(x => !x.StartsWith("META-INF")))
                {
                    WriteEntryHashes(fileProvider, infFile, msManifestFile, msSignatureFileBody);
                }

                //compute the hash on the entirety of the manifest file for the SF file
                msManifestFile.Seek(0, SeekOrigin.Begin);
                var manifestFileHash = _sha.ComputeHash(msManifestFile);

                //write the SF to memory then copy it out to the actual file- contents will be needed later to use for signing, don't want to hit the zip stream twice

                byte[] sigFileBytes = null;

                using (StreamWriter swSignatureFile = GetSW(msSigFile))
                {
                    swSignatureFile.WriteLine("Signature-Version: 1.0");
                    swSignatureFile.WriteLine($"SHA1-Digest-Manifest: {Convert.ToBase64String(manifestFileHash)}");
                    swSignatureFile.WriteLine("Created-By: emulamer");
                    swSignatureFile.WriteLine();
                }
                msSignatureFileBody.Seek(0, SeekOrigin.Begin);
                msSignatureFileBody.CopyTo(msSigFile);
                msSigFile.Seek(0, SeekOrigin.Begin);
                sigFileBytes = msSigFile.ToArray();

                //get the key block (all the hassle distilled into one line), then write it out to the RSA file
                keyBlock = SignIt(sigFileBytes);

                //delete all the META-INF stuff that exists already
                fileProvider.DeleteFiles("META-INF*");

                //write the 3 files
                msManifestFile.Seek(0, SeekOrigin.Begin);

                fileProvider.Write("META-INF/MANIFEST.MF", msManifestFile.ToArray(), true, true);

                fileProvider.Write("META-INF/BS.SF", sigFileBytes, true, true);

                fileProvider.Write("META-INF/BS.RSA", keyBlock, true, true);
                fileProvider.Save();
            }
            finally
            {
                if (msManifestFile != null)
                {
                    msManifestFile.Dispose();
                }
                if (msSignatureFileBody != null)
                {
                    msSignatureFileBody.Dispose();
                }
                if (msManifestFile != null)
                {
                    msManifestFile.Dispose();
                }
                if (msSigFile != null)
                {
                    msSigFile.Dispose();
                }
            }
        }
コード例 #17
0
 protected abstract QaeConfig GetQaeConfig(IAssetsFileProvider prov);
コード例 #18
0
        //private void UpdateSaberConfig(AssetsManager manager)
        //{
        //    var currentSaber = GetCurrentSaberID(manager);
        //    if (saberInfo == null || saberInfo.ID == null)
        //    {
        //        Log.LogMsg("No SaberID provided, saber will not be changed.");
        //        return;
        //    }
        //    if (saberInfo.ID.ToLower() == currentSaber.ToLower())
        //    {
        //        Log.LogMsg("Current saber ID is already set, no change needed.");
        //        return;
        //    }
        //}

        private void UpdateMusicConfig(AssetsManager manager, BeatSaberQuestomConfig config, IAssetsFileProvider apkFileProvider)
        {
            //get the old config before we start on this
            var originalConfig = GetConfig(manager, false);
            var songsAssetFile = manager.GetAssetsFile(BSConst.KnownFiles.SongsAssetsFilename);

            foreach (var playlist in config.Playlists)
            {
                UpdatePlaylistConfig(manager, playlist);
            }

            //open the assets with the main levels collection, find the file index of sharedassets17.assets, and add the playlists to it
            var mainLevelsFile = manager.GetAssetsFile(BSConst.KnownFiles.MainCollectionAssetsFilename);
            var file17Index    = mainLevelsFile.GetFileIDForFilename(BSConst.KnownFiles.SongsAssetsFilename);
            var mainLevelPack  = GetMainLevelPack(manager);


            var packsToUnlink = mainLevelPack.BeatmapLevelPacks.Where(x => !HideOriginalPlaylists || !BSConst.KnownLevelPackIDs.Contains(x.Object.PackID)).ToList();
            var packsToRemove = mainLevelPack.BeatmapLevelPacks.Where(x => !BSConst.KnownLevelPackIDs.Contains(x.Object.PackID) && !config.Playlists.Any(y => y.PlaylistID == x.Object.PackID)).Select(x => x.Object).ToList();

            foreach (var unlink in packsToUnlink)
            {
                mainLevelPack.BeatmapLevelPacks.Remove(unlink);
                unlink.Dispose();
            }

            var oldSongs = originalConfig.Playlists.SelectMany(x => x.SongList).Select(x => x.LevelData).Distinct();
            var newSongs = config.Playlists.SelectMany(x => x.SongList).Select(x => x.LevelData).Distinct();

            //don't allow removal of the actual tracks or level packs that are built in, although you can unlink them from the main list
            var removeSongs = oldSongs.Where(x => !newSongs.Contains(x) && !BSConst.KnownLevelIDs.Contains(x.LevelID)).Distinct().ToList();

            var addedSongs = newSongs.Where(x => !oldSongs.Contains(x));

            var removedPlaylistCount = originalConfig.Playlists.Where(x => !config.Playlists.Any(y => y.PlaylistID == x.PlaylistID)).Count();
            var newPlaylistCount     = config.Playlists.Where(x => !originalConfig.Playlists.Any(y => y.PlaylistID == x.PlaylistID)).Count();
            //
            //
            //TODO: clean up cover art, it's leaking!
            //
            //
            List <string> audioFilesToDelete = new List <string>();

            removeSongs.ForEach(x => RemoveLevelAssets(manager, x, audioFilesToDelete));

            packsToRemove.ForEach(x => RemoveLevelPackAssets(manager, x));

            //relink all the level packs in order
            var addPacks = config.Playlists.Select(x => x.LevelPackObject.PtrFrom(mainLevelPack));

            mainLevelPack.BeatmapLevelPacks.AddRange(addPacks);

            //do a first loop to guess at the file size
            Int64 originalApkSize = new FileInfo(_apkFilename).Length;
            Int64 sizeGuess       = originalApkSize;

            foreach (var pl in config.Playlists)
            {
                foreach (var sng in pl.SongList)
                {
                    if (sng.SourceOgg != null)
                    {
                        var clip = sng.LevelData.AudioClip.Object;
                        sizeGuess += new FileInfo(sng.SourceOgg).Length;
                    }
                }
            }
            foreach (var toDelete in audioFilesToDelete)
            {
                sizeGuess -= apkFileProvider.GetFileSize(BSConst.KnownFiles.AssetsRootPath + toDelete);
            }

            Log.LogMsg("");
            Log.LogMsg("Playlists:");
            Log.LogMsg($"  Added:   {newPlaylistCount}");
            Log.LogMsg($"  Removed: {removedPlaylistCount}");
            Log.LogMsg("");
            Log.LogMsg("Songs:");
            Log.LogMsg($"  Added:   {addedSongs.Count()}");
            Log.LogMsg($"  Removed: {removeSongs.Count()}");
            Log.LogMsg("");
            Log.LogMsg($"Original APK size:     {originalApkSize:n0}");
            Log.LogMsg($"Guesstimated new size: {sizeGuess:n0}");
            Log.LogMsg("");

            if (sizeGuess > Int32.MaxValue)
            {
                Log.LogErr("***************ERROR*****************");
                Log.LogErr($"Guesstimating a file size around {sizeGuess / (Int64)1000000}MB , this will crash immediately upon launch.");
                Log.LogErr($"The file size MUST be less than {Int32.MaxValue / (int)1000000}MB");
                Log.LogErr("***************ERROR*****************");
                throw new OverflowException("File might exceed 2.1GB, aborting.");
            }

            ////////START WRITING DATA



            //todo: save here?


            foreach (var pl in config.Playlists)
            {
                foreach (var sng in pl.SongList)
                {
                    if (sng.SourceOgg != null)
                    {
                        var clip = sng.LevelData.AudioClip.Object;
                        apkFileProvider.WriteFile(sng.SourceOgg, BSConst.KnownFiles.AssetsRootPath + clip.Resource.Source, true, false);
                        //saftey check to make sure we aren't removing a file we just put here
                        if (audioFilesToDelete.Contains(clip.Resource.Source))
                        {
                            Log.LogErr($"Level id '{sng.LevelData.LevelID}' wrote file '{clip.Resource.Source}' that was on the delete list...");
                            audioFilesToDelete.Remove(clip.Resource.Source);
                        }
                    }

                    //todo: save on some interval to save ram?
                }
            }

            if (audioFilesToDelete.Count > 0)
            {
                Log.LogMsg($"Deleting {audioFilesToDelete.ToString()} audio files");
                foreach (var toDelete in audioFilesToDelete)
                {
                    //Log.LogMsg($"Deleting audio file {toDelete}");
                    apkFileProvider.Delete(BSConst.KnownFiles.AssetsRootPath + toDelete);
                }
            }
        }
コード例 #19
0
 public AssetsManager(IAssetsFileProvider fileProvider, Dictionary <string, Type> classNameToTypes, bool lazyLoad = false)
 {
     _fileProvider    = fileProvider;
     LazyLoad         = lazyLoad;
     ClassNameToTypes = classNameToTypes;
 }