예제 #1
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);
                }
            }
        }