Example #1
0
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(Playlist.PlaylistID))
            {
                throw new Exception("PlaylistID must be provided.");
            }

            if (string.IsNullOrEmpty(Playlist.PlaylistName))
            {
                throw new Exception($"PlaylistName must be provided for ID {Playlist.PlaylistName}");
            }

            var songsAssetFile = context.Engine.GetSongsAssetsFile();
            BeatmapLevelPackObject levelPack = null;

            if (context.Cache.PlaylistCache.ContainsKey(Playlist.PlaylistID))
            {
                Log.LogMsg($"Playlist {Playlist.PlaylistID} will be updated");
                levelPack                = context.Cache.PlaylistCache[Playlist.PlaylistID].Playlist;
                levelPack.PackName       = Playlist.PlaylistName;
                Playlist.LevelPackObject = levelPack;
                OpCommon.UpdateCoverImage(Playlist, context, songsAssetFile);
            }
            else
            {
                levelPack = OpCommon.CreatePlaylist(context, Playlist, songsAssetFile);
            }
        }
        internal override void PerformOp(OpContext context)
        {
            var    asset   = _locator.Locate(context.Manager, false);
            string oldName = null;

            if (asset as IHaveName != null && !_allowOverwriteName)
            {
                oldName = (asset as IHaveName).Name;
            }
            using (var ms = new MemoryStream(_replaceDataWith))
            {
                using (AssetsReader reader = new AssetsReader(ms))
                {
                    asset.ObjectInfo.DataOffset = 0;
                    asset.ObjectInfo.DataSize   = _replaceDataWith.Length;
                    asset.Parse(reader);

                    asset.ObjectInfo.DataOffset = -1;
                    asset.ObjectInfo.DataSize   = -1;
                    if (oldName != null)
                    {
                        (asset as IHaveName).Name = oldName;
                    }
                }
            }
        }
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(PlaylistID))
            {
                throw new InvalidOperationException("PlaylistID must be provided.");
            }
            if (!context.Cache.PlaylistCache.ContainsKey((PlaylistID)))
            {
                throw new InvalidOperationException("Playlist ID was not found.");
            }
            if (Index < 0 || Index > context.Cache.PlaylistCache.Count)
            {
                throw new InvalidOperationException("Index is out of range.");
            }

            var mainCol = context.Engine.GetMainLevelPack();
            var ptr     = mainCol.BeatmapLevelPacks.FirstOrDefault(x => x.Object.PackID == PlaylistID);

            if (ptr == null)
            {
                throw new Exception("Unable to find this playlist in the main level pack!  Cache is out of sync!");
            }

            var packIndex = mainCol.BeatmapLevelPacks.IndexOf(ptr);

            mainCol.BeatmapLevelPacks.Remove(ptr);
            var newIndex = Index;


            if (newIndex >= mainCol.BeatmapLevelPacks.Count)
            {
                mainCol.BeatmapLevelPacks.Add(ptr);
            }
            else
            {
                mainCol.BeatmapLevelPacks.Insert(newIndex, ptr);
            }

            //just to be on the safe side, operate on the cache separately and reorder it
            var playlist = context.Cache.PlaylistCache[PlaylistID];
            var ordered  = context.Cache.PlaylistCache.Values.OrderBy(x => x.Order).ToList();
            var oldIndex = ordered.IndexOf(playlist);

            ordered.Remove(playlist);
            newIndex = Index;


            if (newIndex >= ordered.Count)
            {
                ordered.Add(playlist);
            }
            else
            {
                ordered.Insert(newIndex, playlist);
            }
            for (int i = 0; i < ordered.Count; i++)
            {
                ordered[i].Order = i;
            }
        }
Example #4
0
        public static BeatmapLevelPackObject CreatePlaylist(OpContext context, BeatSaberPlaylist playlist, AssetsFile songsAssetFile)
        {
            Log.LogMsg($"Playlist {playlist.PlaylistID} will be created");
            var levelPack = new BeatmapLevelPackObject(songsAssetFile)
            {
                Enabled           = 1,
                GameObject        = null,
                IsPackAlwaysOwned = true,
                PackID            = playlist.PlaylistID,
                Name     = playlist.PlaylistID + BSConst.NameSuffixes.LevelPack,
                PackName = playlist.PlaylistName
            };

            songsAssetFile.AddObject(levelPack, true);
            var col = new BeatmapLevelCollectionObject(songsAssetFile)
            {
                Name = playlist.PlaylistID + BSConst.NameSuffixes.LevelCollection
            };

            songsAssetFile.AddObject(col, true);
            levelPack.BeatmapLevelCollection = col.PtrFrom(levelPack);
            playlist.LevelPackObject         = levelPack;
            var mainCol = context.Engine.GetMainLevelPack();
            var aoPacks = context.Engine.GetAlwaysOwnedModel();

            mainCol.BeatmapLevelPacks.Add(levelPack.PtrFrom(mainCol));
            aoPacks.AlwaysOwnedPacks.Add(levelPack.PtrFrom(aoPacks));
            context.Cache.PlaylistCache.Add(playlist.PlaylistID, new PlaylistAndSongs()
            {
                Playlist = levelPack, Order = context.Cache.PlaylistCache.Count
            });
            UpdateCoverImage(playlist, context, songsAssetFile);
            return(levelPack);
        }
Example #5
0
        internal override void PerformOp(OpContext context)
        {
            var colorManager = context.Manager.MassFirstOrDefaultAsset <ColorManager>(x => true, false)?.Object;

            if (colorManager == null)
            {
                Log.LogErr($"ChangeColorOp could not get the ColorManager class from assets!");
                throw new Exception("Unable to find the color manager asset!");
            }
            SimpleColorSO color = null;

            switch (_colorType)
            {
            case ColorType.LeftColor:
                color = colorManager.ColorA.Object;
                break;

            case ColorType.RightColor:
                color = colorManager.ColorB.Object;
                break;
            }

            if (color == null)
            {
                Log.LogErr($"Color type {_colorType} not found!");
                throw new Exception($"Color type {_colorType} not found!");
            }

            color.Color.A = (float)_color.A / (float)255;
            color.Color.R = (float)_color.R / (float)255;
            color.Color.G = (float)_color.G / (float)255;
            color.Color.B = (float)_color.B / (float)255;
            color.ObjectInfo.ParentFile.HasChanges = true;
        }
Example #6
0
 internal override void PerformOp(OpContext context)
 {
     if (string.IsNullOrEmpty(SongID))
     {
         throw new InvalidOperationException("SongID must be provided.");
     }
     if (!context.Cache.SongCache.ContainsKey(SongID))
     {
         throw new InvalidOperationException("SongID does not exist.");
     }
     OpCommon.DeleteSong(context, SongID);
 }
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID must be provided.");
            }

            if (!context.Cache.PlaylistCache.ContainsKey(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID does not exist.");
            }

            if (PlaylistID == "CustomSongs")
            {
                throw new InvalidOperationException("Don't delete CustomSongs playlist, it's needed for things.");
            }

            OpCommon.DeletePlaylist(context, PlaylistID, DeleteSongsOnPlaylist);
        }
        internal override void PerformOp(OpContext context)
        {
            Comparer <SongAndPlaylist>     comparer;
            Func <SongAndPlaylist, string> nameGetter;

            switch (SortMode)
            {
            case PlaylistSortMode.Name:
                nameGetter = (s) =>
                {
                    if (s.Song.SongName?.Length < 1)
                    {
                        return("");
                    }
                    return(s.Song.SongName.Substring(0, 1).ToUpper());
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.SongName.ToUpper().CompareTo(s2.Song.SongName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.MaxDifficulty:
                nameGetter = (s) =>
                {
                    var max = s.Song?.DifficultyBeatmapSets?.SelectMany(x => x?.DifficultyBeatmaps)?.Max(x => x?.Difficulty);
                    if (max == null)
                    {
                        return(Difficulty.Easy.ToString());
                    }

                    return(max.ToString());
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)
                               .CompareTo(s2.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.LevelAuthor:
                nameGetter = (s) =>
                {
                    return(s.Song?.LevelAuthorName?.ToUpper() ?? "");
                };
                comparer = Comparer <SongAndPlaylist> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.LevelAuthorName.ToUpper().CompareTo(s2.Song.LevelAuthorName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            default:
                throw new NotImplementedException("Unhandled playlist sort mode.");
            }
            var songList = context.Cache.SongCache.Values.ToArray();

            Array.Sort(songList, comparer);
            var songsAssetFile = context.Engine.GetSongsAssetsFile();
            PlaylistAndSongs currentPlaylist = null;
            int    plCtr            = 0;
            string previousSongName = "";

            for (int i = 0; i < songList.Length; i++)
            {
                var song = songList[i];
                if (BSConst.KnownLevelIDs.Contains(song.Song.LevelID) || BSConst.KnownLevelPackIDs.Contains(song.Playlist.PackID))
                {
                    continue;
                }
                var curSongName = nameGetter(song);
                var packID      = $"Auto_{curSongName}";
                if (currentPlaylist == null || currentPlaylist.Playlist.PackID != packID)
                {
                    bool newPlaylist = true;
                    if (currentPlaylist != null && SortMode == PlaylistSortMode.Name)
                    {
                        if (plCtr < MaxPerNamePlaylist)
                        {
                            newPlaylist = false;
                        }
                        else
                        {
                            currentPlaylist.Playlist.PackName += " - " + previousSongName;
                        }
                    }
                    if (newPlaylist)
                    {
                        if (!context.Cache.PlaylistCache.ContainsKey(packID))
                        {
                            OpCommon.CreatePlaylist(context, new Models.BeatSaberPlaylist()
                            {
                                PlaylistID   = packID,
                                PlaylistName = curSongName
                            }, songsAssetFile);
                            currentPlaylist = context.Cache.PlaylistCache[packID];
                        }
                        else
                        {
                            currentPlaylist = context.Cache.PlaylistCache[packID];
                            currentPlaylist.Playlist.PackName = curSongName;
                        }

                        plCtr = 0;
                    }
                }

                //update assets
                var oldPl  = context.Cache.PlaylistCache[song.Playlist.PackID];
                var oldPtr = oldPl.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Where(x => x.Object.LevelID == song.Song.LevelID).First();
                oldPtr.Dispose();
                oldPl.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(oldPtr);
                currentPlaylist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(song.Song.PtrFrom(currentPlaylist.Playlist.BeatmapLevelCollection.Object));

                //update cache
                oldPl.Songs.Remove(song.Song.LevelID);
                song.Playlist = currentPlaylist.Playlist;
                currentPlaylist.Songs.Add(song.Song.LevelID, new OrderedSong()
                {
                    Song = song.Song, Order = plCtr
                });

                plCtr++;
                previousSongName = curSongName;
                if (SortMode == PlaylistSortMode.Name && i == songList.Length - 1)
                {
                    currentPlaylist.Playlist.PackName += " - " + curSongName;
                }
            }
            if (RemoveEmptyPlaylists)
            {
                foreach (var pl in context.Cache.PlaylistCache.ToList())
                {
                    //leave CustomSongs alone
                    if (pl.Value.Songs.Count < 1 && pl.Key != "CustomSongs")
                    {
                        OpCommon.DeletePlaylist(context, pl.Key, false);
                    }
                }
            }
        }
Example #9
0
        public static void DeleteSong(OpContext context, string songID)
        {
            var songsAssetFile = context.Engine.GetSongsAssetsFile();
            var song           = context.Cache.SongCache[songID];
            var songPtr        = song.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.FirstOrDefault(x => x.Object == song.Song);

            if (songPtr == null)
            {
                throw new Exception($"Song pointer is null trying to delete song ID {songID}");
            }
            try
            {
                song.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(songPtr);
                songPtr.Dispose();
                //don't delete built in songs
                if (!BSConst.KnownLevelIDs.Contains(songID))
                {
                    if (song.Song.AudioClip?.Target?.Object != null)
                    {
                        songsAssetFile.DeleteObject(song.Song.AudioClip.Object);
                    }
                    else
                    {
                        Log.LogErr($"Trying to delete song ID {songID} and audio clip is null!");
                    }
                    if (song.Song?.CoverImageTexture2D?.Target?.Object != null)
                    {
                        songsAssetFile.DeleteObject(song.Song.CoverImageTexture2D.Object);
                    }
                    else
                    {
                        Log.LogErr($"Trying to delete song ID {songID} and cover image is null!");
                    }
                    if (song.Song.CoverImageTexture2D != null)
                    {
                        song.Song.CoverImageTexture2D.Dispose();
                    }
                    if (song?.Song?.DifficultyBeatmapSets == null)
                    {
                        Log.LogErr($"Trying to delete song id {songID}, but DifficultyBeatmapSets is null!");
                    }
                    else
                    {
                        song.Song.DifficultyBeatmapSets.ForEach(x =>
                        {
                            if (x?.DifficultyBeatmaps == null)
                            {
                                Log.LogErr($"Trying to delete song id {songID} beatmapset, but DifficultyBeatmaps is null!");
                            }
                            else
                            {
                                x.DifficultyBeatmaps.ForEach(y =>
                                {
                                    if (y != null && y.BeatmapDataPtr != null)
                                    {
                                        if (y?.BeatmapDataPtr?.Object != null)
                                        {
                                            songsAssetFile.DeleteObject(y.BeatmapDataPtr.Object);
                                        }
                                        else
                                        {
                                            Log.LogErr($"Trying to delete song id {songID} but BeatmapDataPtr.Object is null!");
                                        }
                                        y.BeatmapDataPtr.Dispose();
                                    }
                                    else
                                    {
                                        Log.LogErr($"Trying to delete song id {songID} but BeatmapDataPtr is null!");
                                    }
                                });
                            }
                            x.BeatmapCharacteristic.Dispose();
                        });
                    }
                    songsAssetFile.DeleteObject(song.Song);
                    context.Engine.QueuedFileOperations.Add(new QueuedFileOp()
                    {
                        Tag = song.Song.LevelID, Type = QueuedFileOperationType.DeleteFolder, TargetPath = context.Config.SongsPath.CombineFwdSlash(songID)
                    });
                }
                context.Cache.SongCache.Remove(song.Song.LevelID);
                context.Cache.PlaylistCache[song.Playlist.PackID].Songs.Remove(song.Song.LevelID);
            }
            catch (Exception ex)
            {
                Log.LogErr($"Exception deleting song ID {songID}!", ex);
            }
        }
Example #10
0
 internal override void PerformOp(OpContext context)
 {
     context.Engine.QueuedFileOperations.Add(this);
 }
Example #11
0
        public static void DeletePlaylist(OpContext context, string playlistID, bool deleteSongsOnPlaylist)
        {
            var playlist = context.Cache.PlaylistCache[playlistID];

            if (deleteSongsOnPlaylist)
            {
                try
                {
                    foreach (var song in playlist.Songs.ToList())
                    {
                        try
                        {
                            OpCommon.DeleteSong(context, song.Key);
                        }
                        catch (Exception ex)
                        {
                            Log.LogErr($"Exception trying to delete song id {song.Key} while deleting playlist id {playlist.Playlist.PackID}, will be unlinked in cache.  This may leave unused data in the assets.", ex);
                            try
                            {
                                context.Cache.SongCache.Remove(song.Value.Song.LevelID);
                                playlist.Songs.Remove(song.Value.Song.LevelID);
                            }
                            catch (Exception ex2)
                            {
                                Log.LogErr($"Exception cleaning up cache for song id {song.Key} in playlist if {playlist.Playlist.PackID} while recovering from a failed delete.", ex2);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    //really this shouldn't ever get hit anymore.  Probably can remove it.
                    Log.LogErr($"Deleting songs on playlist ID {playlist?.Playlist?.PackID} failed! Attempting to recover by removing links to songs, although this may leave extra stuff in assets!");
                    try
                    {
                        var bmCol = playlist?.Playlist?.BeatmapLevelCollection?.Object?.BeatmapLevels?.ToList();
                        if (bmCol != null)
                        {
                            bmCol.ForEach(x => { playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(x); x.Dispose(); });
                        }
                    }
                    catch (Exception ex2)
                    {
                        Log.LogErr($"Failed to recover by removing song pointers while deleting playlist {playlist?.Playlist?.PackID}!  This will definitely leave stuff in assets.", ex2);
                    }
                }
                playlist.Songs.Clear();
            }
            //this should be done in song delete already
            //playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.ForEach(x => { x.Target.ParentFile.DeleteObject(x.Object); x.Dispose(); });
            var mlp    = context.Engine.GetMainLevelPack();
            var aop    = context.Engine.GetAlwaysOwnedModel();
            var mlpptr = mlp.BeatmapLevelPacks.FirstOrDefault(x => x.Object.PackID == playlist.Playlist.PackID);
            var aopptr = aop.AlwaysOwnedPacks.FirstOrDefault(x => x.Object.PackID == playlist.Playlist.PackID);

            if (mlpptr != null)
            {
                mlp.BeatmapLevelPacks.Remove(mlpptr);
                mlpptr.Dispose();
            }
            else
            {
                Log.LogErr($"The playlist id {playlist.Playlist.PackID} didn't exist in the main level packs");
            }
            if (aopptr != null)
            {
                aop.AlwaysOwnedPacks.Remove(aopptr);
                aopptr.Dispose();
            }
            else
            {
                Log.LogErr($"The playlist id {playlist.Playlist.PackID} didn't exist in the always owned level packs");
            }
            //don't delete built in packs assets, just unlink them
            if (!BSConst.KnownLevelPackIDs.Contains(playlist.Playlist.PackID))
            {
                var plParent = playlist.Playlist.ObjectInfo.ParentFile;
                plParent.DeleteObject(playlist.Playlist.CoverImage.Object.RenderData.Texture.Object);
                playlist.Playlist.CoverImage.Object.RenderData.Texture.Dispose();
                plParent.DeleteObject(playlist.Playlist.CoverImage.Object);
                plParent.DeleteObject(playlist.Playlist);
                playlist.Playlist.CoverImage.Dispose();
            }
            context.Cache.PlaylistCache.Remove(playlistID);
        }
Example #12
0
        public static void UpdateCoverImage(BeatSaberPlaylist playlist, OpContext context, AssetsFile songsAssetFile)
        {
            CustomLevelLoader loader = new CustomLevelLoader(songsAssetFile, context.Config);

            if (playlist.CoverImageBytes != null && playlist.CoverImageBytes.Length > 0)
            {
                Log.LogMsg($"Loading cover art for playlist ID '{playlist.PlaylistID}'");

                var oldCoverImage = playlist?.LevelPackObject?.CoverImage;
                var oldTex        = playlist?.LevelPackObject?.CoverImage?.Object?.RenderData?.Texture;

                //todo: verify this is a good place to delete stuff
                try
                {
                    playlist.CoverArtSprite             = loader.LoadPackCover(playlist.PlaylistID, playlist.CoverImageBytes);
                    playlist.LevelPackObject.CoverImage = playlist.CoverArtSprite.PtrFrom(playlist.LevelPackObject);
                }
                catch (Exception ex)
                {
                    Log.LogErr("Exception in step 1!", ex);
                    throw;
                }
                try
                {
                    //don't erase base content from the assets, although this definitely leaks textures if you keep switching the stock level pack picture
                    if (!BSConst.KnownLevelPackIDs.Contains(playlist.PlaylistID))
                    {
                        if (oldTex != null)
                        {
                            if (oldTex?.Object != null)
                            {
                                songsAssetFile.DeleteObject(oldTex.Object);
                            }

                            oldTex.Dispose();
                        }
                        if (oldCoverImage != null)
                        {
                            if (oldCoverImage.Object != null)
                            {
                                songsAssetFile.DeleteObject(oldCoverImage.Object);
                            }

                            oldCoverImage.Dispose();
                        }
                    }
                }
                catch (Exception ex)
                {
                    Log.LogErr("Exception trying to clean up playlist cover art!  This may leak cover images!", ex);
                }
            }
            else
            {
                try
                {
                    if (playlist.LevelPackObject.CoverImage != null)
                    {
                        playlist.CoverArtSprite = playlist.LevelPackObject.CoverImage.Object;
                    }
                    else
                    {
                        playlist.CoverArtSprite = loader.LoadPackCover(playlist.PlaylistID, null);
                    }
                }
                catch (Exception ex)
                {
                    Log.LogErr("Exception in the cover art sprite part!", ex);
                    throw;
                }
                try
                {
                    playlist.LevelPackObject.CoverImage = playlist.CoverArtSprite.PtrFrom(playlist.LevelPackObject);
                }
                catch (Exception ex)
                {
                    Log.LogErr("Exception in the final step!", ex);
                    throw;
                }
            }
            //try queueing a file write op to output the playlist cover image
            try
            {
                var tex = playlist.LevelPackObject?.CoverImage?.Object?.RenderData?.Texture?.Object;
                if (tex == null)
                {
                    throw new Exception("Texture couldn't be loaded from the playlist even though it should have just been set...");
                }

                var qfo = new QueuedFileOp()
                {
                    TargetPath = context.Config.PlaylistsPath.CombineFwdSlash(playlist.PlaylistID + ".png"),
                    Type       = QueuedFileOperationType.WriteFile,
                    SourceData = Utils.ImageUtils.Instance.TextureToPngBytes(tex)
                };
                context.Engine.QueuedFileOperations.Add(qfo);
            }
            catch (Exception ex)
            {
                Log.LogErr($"Exception queueing write op for playlist art on {playlist.PlaylistID}!", ex);
            }
        }
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(SongID))
            {
                throw new InvalidOperationException("SongID must be provided.");
            }
            if (string.IsNullOrEmpty(ToPlaylistID))
            {
                throw new InvalidOperationException("ToPlaylistID must be provided.");
            }

            if (!context.Cache.SongCache.ContainsKey(SongID))
            {
                throw new InvalidOperationException("SongID could not be found.");
            }
            if (!context.Cache.PlaylistCache.ContainsKey(ToPlaylistID))
            {
                throw new InvalidOperationException("ToPlaylistID could not be found.");
            }

            var song       = context.Cache.SongCache[SongID];
            var toPlaylist = context.Cache.PlaylistCache[ToPlaylistID];

            var songPtr = song.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.FirstOrDefault(x => x.Object == song.Song);

            if (songPtr == null)
            {
                throw new Exception($"Unable to find the song pointer for song id {song.Song.LevelID} in the playlist it is moving from ({song.Playlist.PackID}).");
            }
            song.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(songPtr);
            songPtr.Dispose();
            bool inserted = false;

            if (Index.HasValue)
            {
                if (Index.Value >= toPlaylist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Count)
                {
                    Log.LogErr($"Song ID {SongID} moved to playlist {ToPlaylistID} but it specified an out of range index of {Index.Value}, it will be put at the end.");
                }
                else
                {
                    toPlaylist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Insert(Index.Value, song.Song.PtrFrom(toPlaylist.Playlist));
                    inserted = true;
                }
            }
            if (!inserted)
            {
                toPlaylist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(song.Song.PtrFrom(toPlaylist.Playlist));
            }

            //keep the cache updated
            context.Cache.PlaylistCache[song.Playlist.PackID].Songs.Remove(song.Song.LevelID);
            song.Playlist = toPlaylist.Playlist;
            toPlaylist.Songs.Add(song.Song.LevelID, new OrderedSong()
            {
                Song = song.Song, Order = toPlaylist.Songs.Count
            });

            //if a song's been moved to a playlist, make sure it isn't going to be deleted
            var qfos = context.Engine.QueuedFileOperations.Where(x => x.Tag == SongID && x.Type == QueuedFileOperationType.DeleteFolder || x.Type == QueuedFileOperationType.DeleteFile).ToList();

            foreach (var q in qfos)
            {
                context.Engine.QueuedFileOperations.Remove(q);
            }
        }
Example #14
0
 internal abstract void PerformOp(OpContext context);
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(SongID))
            {
                throw new InvalidOperationException("SongID must be provided.");
            }
            if (!context.Cache.SongCache.ContainsKey(SongID))
            {
                throw new InvalidOperationException("SongID was not found.");
            }
            var songCache     = context.Cache.SongCache[SongID];
            var playlistCache = context.Cache.PlaylistCache[songCache.Playlist.PackID];

            if (Index < 0 || Index > playlistCache.Songs.Count)
            {
                throw new InvalidOperationException("Index is out of range.");
            }

            var ptr = playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.FirstOrDefault(x => x.Object.LevelID == SongID);

            if (ptr == null)
            {
                throw new Exception("Unable to find song pointer!  Cache is out of sync!");
            }
            var songIndex = playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.IndexOf(ptr);

            playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(ptr);
            var newIndex = Index;

            if (newIndex >= playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Count)
            {
                playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(ptr);
            }
            else
            {
                playlistCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Insert(newIndex, ptr);
            }

            //do the cache separately to be safe about it
            var ordered  = playlistCache.Songs.Values.OrderBy(x => x.Order).ToList();
            var sng      = ordered.First(x => x.Song.LevelID == SongID);
            var oldIndex = ordered.IndexOf(sng);

            ordered.Remove(sng);
            newIndex = Index;
            if (newIndex >= ordered.Count)
            {
                ordered.Add(sng);
            }
            else
            {
                ordered.Insert(newIndex, sng);
            }

            for (int i = 0; i < ordered.Count; i++)
            {
                ordered[i].Order = i;
            }

            //if a song's been moved in a playlist, make sure it isn't going to be deleted
            var qfos = context.Engine.QueuedFileOperations.Where(x => x.Tag == SongID && x.Type == QueuedFileOperationType.DeleteFolder || x.Type == QueuedFileOperationType.DeleteFile).ToList();

            foreach (var q in qfos)
            {
                context.Engine.QueuedFileOperations.Remove(q);
            }
        }
Example #16
0
 internal override void PerformOp(OpContext context)
 {
     context.Engine.ModManager.SetModStatus(Definition, TargetModStatus);
 }
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(Song.SongID))
            {
                throw new InvalidOperationException("SongID must be set on the song!");
            }
            if (string.IsNullOrEmpty(Song.CustomSongPath))
            {
                throw new InvalidOperationException("CustomSongPath must be set on the song!");
            }
            if (!context.Cache.PlaylistCache.ContainsKey(PlaylistID))
            {
                throw new KeyNotFoundException($"PlaylistID {PlaylistID} not found in the cache!");
            }
            bool exists = context.Cache.SongCache.ContainsKey(Song.SongID);

            if (exists && !OverwriteIfExists)
            {
                throw new AddSongException(AddSongFailType.SongExists, $"SongID {Song.SongID} already exists!");
            }

            if (exists && OverwriteIfExists)
            {
                OpCommon.DeleteSong(context, Song.SongID);
            }

            if (context.Cache.SongCache.ContainsKey(Song.SongID))
            {
                throw new AddSongException(AddSongFailType.SongExists, $"SongID {Song.SongID} already exists, even though it should have been deleted to be replaced!");
            }

            BeatmapLevelDataObject level = null;

            try
            {
                var songsAssetFile       = context.Engine.GetSongsAssetsFile();
                CustomLevelLoader loader = new CustomLevelLoader(songsAssetFile, context.Config);
                var deser = loader.DeserializeFromJson(Song.CustomSongPath, Song.SongID);
                level = loader.LoadSongToAsset(deser, Song.CustomSongPath, true);
            }
            catch (Exception ex)
            {
                throw new Exception($"Exception loading custom song folder '{Song.CustomSongPath}' for SongID {Song.SongID}", ex);
            }

            if (level == null)
            {
                throw new AddSongException(AddSongFailType.InvalidFormat, $"Song at folder '{Song.CustomSongPath}' for SongID {Song.SongID} failed to load");
            }

            Song.LevelData       = level;
            Song.LevelAuthorName = level.LevelAuthorName;
            Song.SongAuthorName  = level.SongAuthorName;
            Song.SongName        = level.SongName;
            Song.SongSubName     = level.SongSubName;
            var playlist = context.Cache.PlaylistCache[PlaylistID];

            playlist.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(Song.LevelData.PtrFrom(playlist.Playlist.BeatmapLevelCollection.Object));
            playlist.Songs.Add(Song.SongID, new OrderedSong()
            {
                Song = Song.LevelData, Order = playlist.Songs.Count
            });
            context.Cache.SongCache.Add(Song.SongID, new SongAndPlaylist()
            {
                Playlist = playlist.Playlist, Song = Song.LevelData
            });
            var qfos = context.Engine.QueuedFileOperations.Where(x => x.Tag == Song.SongID && x.Type == QueuedFileOperationType.DeleteFolder || x.Type == QueuedFileOperationType.DeleteFile).ToList();

            foreach (var q in qfos)
            {
                context.Engine.QueuedFileOperations.Remove(q);
            }
        }
 public AssetOpManager(OpContext context)
 {
     _context = context;
 }
Example #19
0
        internal override void PerformOp(OpContext context)
        {
            if (string.IsNullOrEmpty(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID must be provided.");
            }

            if (!context.Cache.PlaylistCache.ContainsKey(PlaylistID))
            {
                throw new InvalidOperationException("Playlist ID does not exist.");
            }

            var plCache = context.Cache.PlaylistCache[PlaylistID];

            var songList = plCache.Songs.Values.ToArray();
            Comparer <OrderedSong> comparer;

            switch (SortMode)
            {
            case PlaylistSortMode.Name:
                comparer = Comparer <OrderedSong> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.SongName.ToUpper().CompareTo(s2.Song.SongName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.MaxDifficulty:
                comparer = Comparer <OrderedSong> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)
                               .CompareTo(s2.Song.DifficultyBeatmapSets.SelectMany(x => x.DifficultyBeatmaps).Max(x => x.Difficulty)));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            case PlaylistSortMode.LevelAuthor:
                comparer = Comparer <OrderedSong> .Create((s1, s2) =>
                {
                    try
                    {
                        return(s1.Song.LevelAuthorName.ToUpper().CompareTo(s2.Song.LevelAuthorName.ToUpper()));
                    }
                    catch
                    {
                        return(-1);
                    }
                });

                break;

            default:
                throw new NotImplementedException("Unhandled playlist sort mode.");
            }
            Array.Sort(songList, comparer);

            if (Reverse)
            {
                Array.Reverse(songList);
            }

            plCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.ToList().ForEach(x =>
            {
                plCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Remove(x);
                x.Dispose();
            });
            for (int i = 0; i < songList.Count(); i++)
            {
                var song = songList[i];
                song.Order = i;
                plCache.Playlist.BeatmapLevelCollection.Object.BeatmapLevels.Add(song.Song.PtrFrom(plCache.Playlist.BeatmapLevelCollection.Object));
                Log.LogMsg($"{song.Song.SongName}");
            }
        }