public static void Init() { _customLevelLoader = Resources.FindObjectsOfTypeAll <CustomLevelLoader>().FirstOrDefault(); beatmapCharacteristicCollection = _customLevelLoader.GetField <BeatmapCharacteristicCollectionSO>("_beatmapCharacteristicCollection"); Texture2D defaultCoverTex = Texture2D.blackTexture; defaultCoverImage = Sprite.Create(defaultCoverTex, new Rect(0f, 0f, defaultCoverTex.width, defaultCoverTex.height), new Vector2(0.5f, 0.5f)); cachedMediaAsyncLoaderSO = _customLevelLoader.GetField <CachedMediaAsyncLoader>("_cachedMediaAsyncLoaderSO"); }
private static BeatmapCharacteristicCollectionSO GetDefaultGameModes() { CustomLevelLoader customLevelLoader = UnityEngine.Object.FindObjectOfType <CustomLevelLoader>(); if (customLevelLoader == null) { Plugin.Log.Info("customLevelLoader is null"); return(null); } BeatmapCharacteristicCollectionSO defaultGameModes = FieldHelper.Get <BeatmapCharacteristicCollectionSO>(customLevelLoader, "_beatmapCharacteristicCollection"); if (defaultGameModes == null) { Plugin.Log.Warn("defaultGameModes is null"); } return(defaultGameModes); }
//private bool SaberExists(AssetsManager manager, string saberID) //{ // var file11 = manager.GetAssetsFile(BSConst.KnownFiles.File11); // return file11.FindAsset<GameObject>(x => x.Object.Name == $"{saberID}Saber") != null; //} //private string GetCurrentSaberID(AssetsManager manager) //{ // var saberChild = GetSaberObjectParentTransform(manager)?.GameObject?.Object; // if (saberChild == null) // throw new Exception("Couldn't find child saber game object of transform."); // return saberChild.Name.Substring(0, saberChild.Name.Length - 5); //} //private Transform GetSaberObjectParentTransform(AssetsManager manager) //{ // var file11 = manager.GetAssetsFile(BSConst.KnownFiles.File11); // var basicSaberModel = file11.FindAsset<GameObject>(x => x.Object.Name == "BasicSaberModel"); // if (basicSaberModel == null) // throw new Exception("Couldn't find BasicSaberModel!"); // var transform = basicSaberModel.Object.Components.FirstOrDefault(x => x.Object is Transform)?.Object as Transform; // if (transform == null) // throw new Exception("Couldn't find Transform on BasicSaberModel!"); // var saberParent = (transform.Children.FirstOrDefault(x => x.Object is Transform // && ((x.Object as Transform).GameObject?.Object?.Name?.EndsWith("Saber") ?? false)).Object as Transform); // if (saberParent == null) // throw new Exception("Could not find child transform of BasicSaberModel!"); // return saberParent; //} //private void SwapToSaberID(AssetsManager manager, string saberID) //{ // var file11 = manager.GetAssetsFile(BSConst.KnownFiles.File11); // var newSaber = file11.FindAsset<GameObject>(x => x.Object.Name == $"{saberID}Saber")?.Object; // if (newSaber == null) // throw new Exception($"Saber with ID {saberID} does not exist!"); // var newSaberTransform = newSaber.Components.FirstOrDefault(x => x.Object is Transform).Object as Transform; // if (newSaberTransform == null) // throw new Exception($"Saber with ID {saberID} is missing its parent transform!"); // var basicSaberModel = file11.FindAsset<GameObject>(x => x.Object.Name == "BasicSaberModel"); // if (basicSaberModel == null) // throw new Exception("Couldn't find BasicSaberModel!"); // var transform = basicSaberModel.Object.Components.FirstOrDefault(x => x.Object is Transform)?.Object as Transform; // if (transform == null) // throw new Exception("Couldn't find Transform on BasicSaberModel!"); // var saberChild = transform.Children.FirstOrDefault(x => x.Object.GameObject?.Object?.Name?.EndsWith("Saber")??false); // if (saberChild == null) // throw new Exception("Couldn't find a game object on the BasicSaberModel Transform that ended with -Saber!"); // int saberIndex = transform.Children.IndexOf(saberChild); // saberChild.Object.Father = null; // transform.Children[saberIndex] = newSaberTransform.PtrFrom(transform) as ISmartPtr<Transform>; // newSaberTransform.Father = transform.PtrFrom(newSaberTransform); //} #endregion private BeatSaberQuestomConfig GetConfig() { lock (this) { BeatSaberQuestomConfig config = new BeatSaberQuestomConfig(); var mainPack = GetMainLevelPack(); CustomLevelLoader loader = new CustomLevelLoader(GetSongsAssetsFile(), _config); foreach (var packPtr in mainPack.BeatmapLevelPacks) { var pack = packPtr.Target.Object; if (HideOriginalPlaylists && BSConst.KnownLevelPackIDs.Contains(pack.PackID)) { continue; } var packModel = new BeatSaberPlaylist() { PlaylistName = pack.PackName, PlaylistID = pack.PackID, LevelPackObject = pack }; var collection = pack.BeatmapLevelCollection.Object; foreach (var songPtr in collection.BeatmapLevels) { var songObj = songPtr.Object; var songModel = new BeatSaberSong() { LevelAuthorName = songObj.LevelAuthorName, SongID = songObj.LevelID, SongAuthorName = songObj.SongAuthorName, SongName = songObj.SongName, SongSubName = songObj.SongSubName, LevelData = songObj }; songModel.CoverArtFilename = loader.GetCoverImageFilename(songObj); packModel.SongList.Add(songModel); } config.Playlists.Add(packModel); } return(config); } }
internal void MenuLoaded() { if (AreSongsLoading) { //Scene changing while songs are loading. Since we are using a separate thread while loading, this is bad and could cause a crash. //So we have to stop loading. if (_loadingTask != null) { _loadingTask.Cancel(); _loadingCancelled = true; AreSongsLoading = false; LoadingProgress = 0; StopAllCoroutines(); _progressBar.ShowMessage("Loading cancelled\n<size=80%>Press Ctrl+R to refresh</size>"); Logging.Log("Loading was cancelled by player since they loaded another scene."); } } BS_Utils.Gameplay.Gamemode.Init(); if (_customLevelLoader == null) { _customLevelLoader = Resources.FindObjectsOfTypeAll <CustomLevelLoader>().FirstOrDefault(); if (_customLevelLoader) { Texture2D defaultCoverTex = _customLevelLoader.GetField <Texture2D>("_defaultPackCoverTexture2D"); defaultCoverImage = Sprite.Create(defaultCoverTex, new Rect(0f, 0f, defaultCoverTex.width, defaultCoverTex.height), new Vector2(0.5f, 0.5f)); cachedMediaAsyncLoaderSO = _customLevelLoader.GetField <CachedMediaAsyncLoader>("_cachedMediaAsyncLoaderSO"); beatmapCharacteristicCollection = _customLevelLoader.GetField <BeatmapCharacteristicCollectionSO>("_beatmapCharacteristicCollection"); } else { Texture2D defaultCoverTex = Texture2D.blackTexture; defaultCoverImage = Sprite.Create(defaultCoverTex, new Rect(0f, 0f, defaultCoverTex.width, defaultCoverTex.height), new Vector2(0.5f, 0.5f)); } } }
private IEnumerator DelayedSetup() { //Slight delay before grabbing needed objects yield return(new WaitForSeconds(0.1f)); _timeSync = Resources.FindObjectsOfTypeAll <AudioTimeSyncController>().LastOrDefault(x => x.isActiveAndEnabled); _songAudio = _timeSync.GetField <AudioSource>("_audioSource"); _levelLoader = Resources.FindObjectsOfTypeAll <CustomLevelLoader>().First(); _spawnController = Resources.FindObjectsOfTypeAll <BeatmapObjectSpawnController>().LastOrDefault(x => x.isActiveAndEnabled); _originalSpawnMovementData = _spawnController.GetField <BeatmapObjectSpawnMovementData>("_beatmapObjectSpawnMovementData"); _pauseController = Resources.FindObjectsOfTypeAll <PauseController>().LastOrDefault(x => x.isActiveAndEnabled); _callbackController = Resources.FindObjectsOfTypeAll <BeatmapObjectCallbackController>().LastOrDefault(x => x.isActiveAndEnabled); _seManager = Resources.FindObjectsOfTypeAll <NoteCutSoundEffectManager>().LastOrDefault(x => x.isActiveAndEnabled); _beatmapObjectManager = _seManager.GetField <BeatmapObjectManager>("_beatmapObjectManager"); _cancelSource = new CancellationTokenSource(); var level = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.level; if (!(level is CustomPreviewBeatmapLevel)) { yield break; } _currentLevel = level as CustomPreviewBeatmapLevel; //Get DifficultyBeatmap BeatmapDifficulty levelDiff = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.difficulty; BeatmapCharacteristicSO levelCharacteristic = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic; _currentDiffBeatmap = _currentLevel.standardLevelInfoSaveData.difficultyBeatmapSets.First( x => x.beatmapCharacteristicName == levelCharacteristic.serializedName).difficultyBeatmaps.First( x => x.difficulty == levelDiff.ToString()); _originalInitData = _timeSync.GetField <AudioTimeSyncController.InitData>("_initData"); _songStartTime = _originalInitData.startSongTime; //Initialize if everything successfully grabbed _init = true; }
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); } }
private void UpdatePlaylistConfig(AssetsManager manager, BeatSaberPlaylist playlist) { Log.LogMsg($"Processing playlist ID {playlist.PlaylistID}..."); var songsAssetFile = manager.GetAssetsFile(BSConst.KnownFiles.SongsAssetsFilename); CustomLevelLoader loader = new CustomLevelLoader(songsAssetFile); BeatmapLevelPackObject levelPack = songsAssetFile.FindAsset <BeatmapLevelPackObject>(x => x.Object.PackID == playlist.PlaylistID)?.Object; //create a new level pack if one waasn't found if (levelPack == null) { Log.LogMsg($"Level pack for playlist '{playlist.PlaylistID}' was not found and will be created"); 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; levelPack.PackName = playlist.PlaylistName ?? levelPack.PackName; if (playlist.CoverArt != null) { Log.LogMsg($"Loading cover art for playlist ID '{playlist.PlaylistID}'"); playlist.CoverArtSprite = loader.LoadPackCover(playlist.PlaylistID, playlist.CoverArt); playlist.LevelPackObject.CoverImage = playlist.CoverArtSprite.PtrFrom(playlist.LevelPackObject); } else { if (playlist.LevelPackObject.CoverImage != null) { playlist.CoverArtSprite = playlist.LevelPackObject.CoverImage.Object; } else { playlist.CoverArtSprite = loader.LoadPackCover(playlist.PlaylistID, null); } playlist.LevelPackObject.CoverImage = playlist.CoverArtSprite.PtrFrom(playlist.LevelPackObject); } //clear out any levels, we'll add them back var levelCollection = levelPack.BeatmapLevelCollection.Object; levelCollection.BeatmapLevels.ForEach(x => x.Dispose()); levelCollection.BeatmapLevels.Clear(); int songCount = 0; Log.LogMsg($"Processing songs for playlist ID {playlist.PlaylistID}..."); var totalSongs = playlist.SongList.Count(); var songMod = Math.Ceiling((double)totalSongs / (double)10); if (songMod < 1) { songMod = 1; } foreach (var song in playlist.SongList.ToList()) { songCount++; if (songCount % songMod == 0) { Console.WriteLine($"{songCount.ToString().PadLeft(5)} of {totalSongs}..."); } if (UpdateSongConfig(manager, song, loader)) { if (levelCollection.BeatmapLevels.Any(x => x.Object.LevelID == song.LevelData.LevelID)) { Log.LogErr($"Playlist ID '{playlist.PlaylistID}' already contains song ID '{song.SongID}' once, removing the second link"); } else { levelCollection.BeatmapLevels.Add(song.LevelData.PtrFrom(levelCollection)); continue; } } playlist.SongList.Remove(song); } Console.WriteLine($"Proccessed {totalSongs} for playlist ID {playlist.PlaylistID}"); }
private bool UpdateSongConfig(AssetsManager manager, BeatSaberSong song, CustomLevelLoader loader) { var songsAssetFile = manager.GetAssetsFile(BSConst.KnownFiles.SongsAssetsFilename); BeatmapLevelDataObject level = null; if (!string.IsNullOrWhiteSpace(song.SongID)) { var levels = songsAssetFile.FindAssets <BeatmapLevelDataObject>(x => x.Object.LevelID == song.SongID).Select(x => x.Object).ToList(); if (levels.Count() > 0) { if (levels.Count() > 1) { Log.LogErr($"Song ID {song.SongID} already has more than one entry in the assets, this may cause problems!"); } else { Log.LogMsg($"Song ID {song.SongID} exists already and won't be loaded"); } level = levels.First(); song.LevelData = level; return(true); } else { Log.LogMsg($"Song ID '{song.SongID}' does not exist and will be created"); } } if (level != null && !string.IsNullOrWhiteSpace(song.CustomSongFolder)) { Log.LogErr("SongID and CustomSongsFolder are both set and the level already exists. The existing one will be used and CustomSongsFolder won'tbe imported again."); return(false); } //load new song if (!string.IsNullOrWhiteSpace(song.CustomSongFolder)) { try { string oggPath; var deser = loader.DeserializeFromJson(song.CustomSongFolder, song.SongID); var found = songsAssetFile.FindAssets <BeatmapLevelDataObject>(x => x.Object.LevelID == deser.LevelID).Select(x => x.Object).FirstOrDefault(); if (found != null) { Log.LogErr($"No song id was specified, but the level {found.LevelID} is already in the assets, skipping it."); song.LevelData = found; return(true); } level = loader.LoadSongToAsset(deser, song.CustomSongFolder, out oggPath, true); song.SourceOgg = oggPath; } catch (Exception ex) { Log.LogErr($"Exception loading custom song folder '{song.CustomSongFolder}', skipping it", ex); return(false); } if (level == null) { Log.LogErr($"Song at folder '{song.CustomSongFolder}' failed to load, skipping it"); return(false); } song.LevelData = level; return(true); } //level == null && string.IsNullOrWhiteSpace(song.CustomSongFolder) Log.LogErr($"Song ID '{song.SongID}' either was not specified or could not be found and no CustomSongFolder was specified, skipping it."); return(false); }
protected virtual void BackToMenu() { CustomLevelLoader.LoadLevel("Menu"); }
private void Restart() { CustomLevelLoader.LoadLevel("Game"); }
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 void PlayGame() { CustomLevelLoader.LoadLevel("Game"); }