IEnumerator WaitForLoad() { bool loaded = false; while (!loaded) { playerHeadAndObstacleInteraction = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault()?.GetPrivateField <PlayerHeadAndObstacleInteraction>("_playerHeadAndObstacleInteraction"); if (playerHeadAndObstacleInteraction == null) { yield return(new WaitForSeconds(0.1f)); } else { loaded = true; } } yield return(new WaitForSeconds(0.1f)); }
private IEnumerator WaitForLoad() { bool loaded = false; while (!loaded) { multi = Resources.FindObjectsOfTypeAll <ScoreMultiplierUIController>().FirstOrDefault(); score = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); obstacles = Resources.FindObjectsOfTypeAll <PlayerHeadAndObstacleInteraction>().FirstOrDefault(); comboPanel = GameObject.Find("ComboPanel"); if (multi == null || score == null || obstacles == null || comboPanel == null) { yield return(new WaitForSeconds(0.01f)); } else { loaded = true; } } Init(); }
private Task WaitForLoad() { return(Task.Run(() => { var loaded = false; while (!loaded) { multi = Resources.FindObjectsOfTypeAll <ScoreMultiplierUIController>().FirstOrDefault(); score = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); ob = Resources.FindObjectsOfTypeAll <PlayerHeadAndObstacleInteraction>().FirstOrDefault(); if (multi == null || score == null || ob == null) { Thread.Sleep(10); } else { loaded = true; } } Init(); })); }
static bool Prefix(ref HeadObstacleLowPassAudioEffect ____headWasInObstacle, MainAudioEffects ____mainAudioEffects, PlayerHeadAndObstacleInteraction ____playerHeadAndObstacleInteraction) { if (PluginConfig.lowPass == false) { bool flag = ____playerHeadAndObstacleInteraction.intersectingObstacles.Count > 0; if (flag == ____headWasInObstacle) { return(true); } if (flag) { //____mainAudioEffects.TriggerLowPass(); } else { ____mainAudioEffects.ResumeNormalSound(); } flag = ____headWasInObstacle; return(false); } else { return(true); } }
private void OnActiveSceneChanged(Scene oldScene, Scene newScene) { GameStatus gameStatus = statusManager.gameStatus; gameStatus.scene = newScene.name; if (newScene.name == "MenuCore") { // Menu gameStatus.scene = "Menu"; Gamemode.Init(); // TODO: get the current song, mode and mods while in menu gameStatus.ResetMapInfo(); gameStatus.ResetPerformance(); // Release references for AfterCutScoreBuffers that don't resolve due to player leaving the map before finishing. noteCutMapping.Clear(); statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "menu"); } else if (newScene.name == "GameCore") { // In game gameStatus.scene = "Song"; gamePauseManager = FindFirstOrDefault <GamePauseManager>(); scoreController = FindFirstOrDefault <ScoreController>(); gameplayManager = Resources.FindObjectsOfTypeAll <StandardLevelGameplayManager>().FirstOrDefault() as MonoBehaviour ?? Resources.FindObjectsOfTypeAll <MissionLevelGameplayManager>().FirstOrDefault(); beatmapObjectCallbackController = FindFirstOrDefault <BeatmapObjectCallbackController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>(); playerHeadAndObstacleInteraction = FindFirstOrDefault <PlayerHeadAndObstacleInteraction>(); gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>(); gameplayCoreSceneSetupData = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData; // Register event listeners // private GameEvent GamePauseManager#_gameDidPauseSignal AddSubscriber(gamePauseManager, "_gameDidPauseSignal", OnGamePause); // private GameEvent GamePauseManager#_gameDidResumeSignal AddSubscriber(gamePauseManager, "_gameDidResumeSignal", OnGameResume); // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int, int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // private GameEvent GameplayManager#_levelFinishedSignal AddSubscriber(gameplayManager, "_levelFinishedSignal", OnLevelFinished); // private GameEvent GameplayManager#_levelFailedSignal AddSubscriber(gameplayManager, "_levelFailedSignal", OnLevelFailed); // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; IDifficultyBeatmap diff = gameplayCoreSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; gameStatus.partyMode = Gamemode.IsPartyActive; gameStatus.mode = Gamemode.GameMode; gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; PlayerSpecificSettings playerSettings = gameplayCoreSceneSetupData.playerSpecificSettings; PracticeSettings practiceSettings = gameplayCoreSceneSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } float modifierMultiplier = gameplayModifiersSO.GetTotalMultiplier(gameplayModifiers); gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.levelAuthorName = level.levelAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; gameStatus.songHash = level.levelID.Substring(0, Math.Min(32, level.levelID.Length)); gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.beatmapLevelData.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.notesCount; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.environmentName = level.environmentSceneInfo.sceneName; gameStatus.maxScore = ScoreController.MaxModifiedScoreForMaxRawScore(ScoreController.MaxRawScoreForNumberOfNotes(diff.beatmapData.notesCount), gameplayModifiers, gameplayModifiersSO); gameStatus.maxRank = RankModel.MaxRankForGameplayModifiers(gameplayModifiers, gameplayModifiersSO).ToString(); try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- var texture = level.GetCoverImageTexture2DAsync(CancellationToken.None).Result; var active = RenderTexture.active; var temporary = RenderTexture.GetTemporary( texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear ); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var cover = new Texture2D(texture.width, texture.height); cover.ReadPixels(new Rect(0, 0, temporary.width, temporary.height), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String( ImageConversion.EncodeToPNG(cover) ); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); gameStatus.modifierMultiplier = modifierMultiplier; gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFail; gameStatus.modBatteryEnergy = gameplayModifiers.batteryEnergy; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modNoArrows = gameplayModifiers.noArrows; gameStatus.modGhostNotes = gameplayModifiers.ghostNotes; gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; gameStatus.modFastNotes = gameplayModifiers.fastNotes; gameStatus.staticLights = playerSettings.staticLights; gameStatus.leftHanded = playerSettings.leftHanded; gameStatus.swapColors = playerSettings.swapColors; gameStatus.playerHeight = playerSettings.playerHeight; gameStatus.disableSFX = playerSettings.disableSFX; gameStatus.noHUD = playerSettings.noTextsAndHuds; gameStatus.advancedHUD = playerSettings.advancedHud; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); } }
private void AddEvents() { if (_leftSaber) { _leftEventManager = _leftSaber.GetComponent <EventManager>(); if (_leftEventManager == null) { _leftEventManager = _leftSaber.AddComponent <EventManager>(); } } if (_rightSaber) { _rightEventManager = _rightSaber.GetComponent <EventManager>(); if (_rightEventManager == null) { _rightEventManager = _rightSaber.AddComponent <EventManager>(); } } if (_leftEventManager) { if (_leftEventManager.OnLevelStart != null) { _leftEventManager.OnLevelStart.Invoke(); } else { return; } } if (_rightEventManager) { if (_rightEventManager.OnLevelStart != null) { _rightEventManager.OnLevelStart.Invoke(); } else { return; } } try { _beatmapObjectSpawnController = Resources.FindObjectsOfTypeAll <BeatmapObjectSpawnController>().FirstOrDefault(); if (_beatmapObjectSpawnController == null) { Logger.Log("Spawn Controller is 'NULL'", LogLevel.Warning); //_beatmapObjectSpawnController = _saberRoot.AddComponent<BeatmapObjectSpawnController>(); } _scoreController = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); if (_scoreController == null) { Logger.Log("Score Controller is 'NULL'", LogLevel.Warning); //_scoreController = _saberRoot.AddComponent<ScoreController>(); } _saberCollisionManager = Resources.FindObjectsOfTypeAll <ObstacleSaberSparkleEffectManager>().FirstOrDefault(); if (_saberCollisionManager == null) { Logger.Log("Collision Manager is 'NULL'", LogLevel.Warning); //_saberCollisionManager = _saberRoot.AddComponent<ObstacleSaberSparkleEffectManager>(); } _gameEnergyCounter = Resources.FindObjectsOfTypeAll <GameEnergyCounter>().FirstOrDefault(); if (_gameEnergyCounter == null) { Logger.Log("Energy Counter is 'NULL'", LogLevel.Warning); //_gameEnergyCounter = _saberRoot.AddComponent<GameEnergyCounter>(); } _beatmapCallback = Resources.FindObjectsOfTypeAll <BeatmapObjectCallbackController>().FirstOrDefault(); if (_beatmapCallback == null) { Logger.Log("Beatmap Callback is 'NULL'", LogLevel.Warning); //_beatmapCallback = _saberRoot.AddComponent<BeatmapObjectCallbackController>(); } _gamePauseManager = Resources.FindObjectsOfTypeAll <GamePauseManager>().FirstOrDefault(); if (_gamePauseManager == null) { Logger.Log("GamePauseManager is 'NULL'", LogLevel.Warning); //_gamePauseManager = _saberRoot.AddComponent<GamePauseManager>(); } _playerHeadAndObstacleInteraction = Resources.FindObjectsOfTypeAll <PlayerHeadAndObstacleInteraction>().FirstOrDefault(); if (_playerHeadAndObstacleInteraction == null) { Logger.Log("PlayerHeadAndObstacleInteraction is 'NULL'", LogLevel.Warning); //_playerHeadAndObstacleInteraction = _saberRoot.AddComponent<PlayerHeadAndObstacleInteraction>(); } if (_beatmapObjectSpawnController) { _beatmapObjectSpawnController.noteWasCutEvent += SliceCallBack; _beatmapObjectSpawnController.noteWasMissedEvent += NoteMissCallBack; } if (_scoreController) { _scoreController.multiplierDidChangeEvent += MultiplierCallBack; _scoreController.comboDidChangeEvent += ComboChangeEvent; } if (_saberCollisionManager) { _saberCollisionManager.sparkleEffectDidStartEvent += SaberStartCollide; _saberCollisionManager.sparkleEffectDidEndEvent += SaberEndCollide; } if (_gameEnergyCounter) { _gameEnergyCounter.gameEnergyDidReach0Event += FailLevelCallBack; } if (_beatmapCallback) { _beatmapCallback.beatmapEventDidTriggerEvent += LightEventCallBack; } //ReflectionUtil.SetPrivateField(_gamePauseManager, "_gameDidResumeSignal", (Action)OnPauseMenuClosed); //For some reason _gameDidResumeSignal isn't public. } catch (Exception ex) { Logger.Log($"{ex.Message}\n{ex.StackTrace}", LogLevel.Error); throw; } try { var mgs = GetGameSceneSetup(); var beatmapData = mgs.GameplayCoreSceneSetupData.difficultyBeatmap.beatmapData; var beatmapLinesData = beatmapData.beatmapLinesData; var LastTime = 0.0f; for (var i = 0; i < beatmapLinesData.Length; i++) { var beatmapObjectsData = beatmapLinesData[i].beatmapObjectsData; for (var j = beatmapObjectsData.Length - 1; j >= 0; j--) { if (beatmapObjectsData[j].beatmapObjectType == BeatmapObjectType.Note) { if (((NoteData)beatmapObjectsData[j]).noteType != NoteType.Bomb) { if (beatmapObjectsData[j].time > LastTime) { LastNoteId = beatmapObjectsData[j].id; LastTime = beatmapObjectsData[j].time; } break; } } } } } catch (Exception ex) { Logger.Log($"{ex.Message}\n{ex.StackTrace}", LogLevel.Error); throw; } }
private void AddEvents() { _leftEventManager = _leftSaber.GetComponent <EventManager>(); if (_leftEventManager == null) { _leftEventManager = _leftSaber.AddComponent <EventManager>(); } _rightEventManager = _rightSaber.GetComponent <EventManager>(); if (_rightEventManager == null) { _rightEventManager = _rightSaber.AddComponent <EventManager>(); } _leftEventManager.OnLevelStart.Invoke(); _rightEventManager.OnLevelStart.Invoke(); try { _beatmapObjectSpawnController = Resources.FindObjectsOfTypeAll <BeatmapObjectSpawnController>().FirstOrDefault(); if (_beatmapObjectSpawnController == null) { Console.WriteLine("SPAWN CONTROLLER NULL"); //_beatmapObjectSpawnController = _saberRoot.AddComponent<BeatmapObjectSpawnController>(); } _scoreController = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); if (_scoreController == null) { Console.WriteLine("SCORE CONTROLLER NULL"); //_scoreController = _saberRoot.AddComponent<ScoreController>(); } _saberCollisionManager = Resources.FindObjectsOfTypeAll <ObstacleSaberSparkleEffectManager>().FirstOrDefault(); if (_saberCollisionManager == null) { Console.WriteLine("COLLISION MANAGER NULL"); //_saberCollisionManager = _saberRoot.AddComponent<ObstacleSaberSparkleEffectManager>(); } _gameEnergyCounter = Resources.FindObjectsOfTypeAll <GameEnergyCounter>().FirstOrDefault(); if (_gameEnergyCounter == null) { Console.WriteLine("energery counter null"); //_gameEnergyCounter = _saberRoot.AddComponent<GameEnergyCounter>(); } _beatmapCallback = Resources.FindObjectsOfTypeAll <BeatmapObjectCallbackController>().FirstOrDefault(); if (_beatmapCallback == null) { Console.WriteLine("BEATMAP CALLBACK NULL"); //_beatmapCallback = _saberRoot.AddComponent<BeatmapObjectCallbackController>(); } _gamePauseManager = Resources.FindObjectsOfTypeAll <GamePauseManager>().FirstOrDefault(); if (_gamePauseManager == null) { Console.WriteLine("GamePauseManager Null"); //_gamePauseManager = _saberRoot.AddComponent<GamePauseManager>(); } _playerHeadAndObstacleInteraction = Resources.FindObjectsOfTypeAll <PlayerHeadAndObstacleInteraction>().FirstOrDefault(); if (_playerHeadAndObstacleInteraction == null) { Console.WriteLine("PlayerHeadAndObstacleInteraction Null"); //_playerHeadAndObstacleInteraction = _saberRoot.AddComponent<PlayerHeadAndObstacleInteraction>(); } _beatmapObjectSpawnController.noteWasCutEvent += SliceCallBack; _beatmapObjectSpawnController.noteWasMissedEvent += NoteMissCallBack; _scoreController.multiplierDidChangeEvent += MultiplierCallBack; _scoreController.comboDidChangeEvent += ComboChangeEvent; _saberCollisionManager.sparkleEffectDidStartEvent += SaberStartCollide; _saberCollisionManager.sparkleEffectDidEndEvent += SaberEndCollide; _gameEnergyCounter.gameEnergyDidReach0Event += FailLevelCallBack; _beatmapCallback.beatmapEventDidTriggerEvent += LightEventCallBack; // ReflectionUtil.SetPrivateField(_gamePauseManager, "_gameDidResumeSignal", (Action)OnPauseMenuClosed); //For some reason _gameDidResumeSignal isn't public. } catch (Exception e) { Console.WriteLine(e); Console.WriteLine(e.Message); throw; } try { StandardLevelSceneSetup mgs = GetGameSceneSetup(); BeatmapData beatmapData = mgs.standardLevelSceneSetupData.difficultyBeatmap.beatmapData; BeatmapLineData[] beatmapLinesData = beatmapData.beatmapLinesData; float LastTime = 0.0f; for (int i = 0; i < beatmapLinesData.Length; i++) { BeatmapObjectData[] beatmapObjectsData = beatmapLinesData[i].beatmapObjectsData; for (int j = beatmapObjectsData.Length - 1; j > 0; j--) { if (beatmapObjectsData[j].beatmapObjectType == BeatmapObjectType.Note) { if (((NoteData)beatmapObjectsData[j]).noteType != NoteType.Bomb) { if (beatmapObjectsData[j].time > LastTime) { LastNoteId = beatmapObjectsData[j].id; LastTime = beatmapObjectsData[j].time; } break; } } } } } catch (Exception e) { Console.WriteLine(e); Console.WriteLine(e.Message); throw; } }
public async void HandleSongStart() { // Check if level data is actually available in BS_Utils before proceeding further. It isn't available in the tutorial if (!BS_Utils.Plugin.LevelData.IsSet) { Plugin.log.Debug("BS_Utils level data is not present. Probably due to the tutorial being active."); return; } GameStatus gameStatus = statusManager.gameStatus; // Check for multiplayer early to abort if needed: gameplay controllers don't exist in multiplayer until later multiplayerSessionManager = FindFirstOrDefaultOptional <MultiplayerSessionManager>(); multiplayerController = FindFirstOrDefaultOptional <MultiplayerController>(); if (multiplayerSessionManager && multiplayerController) { Plugin.log.Debug("Multiplayer Level loaded"); // public event Action<DisconnectedReason> MultiplayerSessionManager#disconnectedEvent; multiplayerSessionManager.disconnectedEvent += OnMultiplayerDisconnected; // public event Action<State> MultiplayerController#stateChangedEvent; multiplayerController.stateChangedEvent += OnMultiplayerStateChanged; // Do nothing until the next state change to Gameplay. if (multiplayerController.state != MultiplayerController.State.Gameplay) { return; } multiplayerLocalActivePlayerFacade = FindFirstOrDefaultOptional <MultiplayerLocalActivePlayerFacade>(); if (multiplayerLocalActivePlayerFacade != null) { multiplayerLocalActivePlayerFacade.playerDidFinishEvent += OnMultiplayerLevelFinished; } } else if (!doDelayedSongStart) { doDelayedSongStart = true; return; } // `wants_to_play_next_level` is set for players who don't want to play the song aka want to spectate aka are not "active". `isSpectating` is apparently not spectating. gameStatus.scene = multiplayerSessionManager.isSpectating || !multiplayerSessionManager.LocalPlayerHasState(NetworkConstants.wantsToPlayNextLevel) ? "Spectator" : "Song"; gameStatus.multiplayer = multiplayerSessionManager.isConnectingOrConnected; pauseController = FindFirstOrDefaultOptional <PauseController>(); scoreController = FindWithMultiplayerFix <ScoreController>(); beatmapObjectManager = (BeatmapObjectManager)scoreControllerBeatmapObjectManagerField.GetValue(scoreController); gameplayManager = FindFirstOrDefaultOptional <StandardLevelGameplayManager>() as MonoBehaviour ?? FindFirstOrDefaultOptional <MissionLevelGameplayManager>(); beatmapObjectCallbackController = FindWithMultiplayerFix <BeatmapObjectCallbackController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindWithMultiplayerFix <AudioTimeSyncController>(); playerHeadAndObstacleInteraction = (PlayerHeadAndObstacleInteraction)scoreControllerHeadAndObstacleInteractionField.GetValue(scoreController); gameSongController = FindWithMultiplayerFix <GameSongController>(); gameEnergyCounter = FindWithMultiplayerFix <GameEnergyCounter>(); if (multiplayerController) { // NOOP } else if (gameplayManager is StandardLevelGameplayManager) { Plugin.log.Debug("Standard Level loaded"); } else if (gameplayManager is MissionLevelGameplayManager) { Plugin.log.Debug("Mission Level loaded"); } gameplayCoreSceneSetupData = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData; // Register event listeners // PauseController doesn't exist in multiplayer if (pauseController != null) { // public event Action PauseController#didPauseEvent; pauseController.didPauseEvent += OnGamePause; // public event Action PauseController#didResumeEvent; pauseController.didResumeEvent += OnGameResume; } // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after CutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int, int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; beatmapObjectManager.noteWasSpawnedEvent += OnNoteWasSpawned; // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; // public event Action GameSongController#songDidFinishEvent; gameSongController.songDidFinishEvent += OnLevelFinished; // public event Action GameEnergyCounter#gameEnergyDidReach0Event; gameEnergyCounter.gameEnergyDidReach0Event += OnEnergyDidReach0Event; if (gameplayManager is ILevelEndActions levelEndActions) { // event Action levelFailedEvent; levelEndActions.levelFailedEvent += OnLevelFailed; } IDifficultyBeatmap diff = gameplayCoreSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; gameStatus.partyMode = Gamemode.IsPartyActive; gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; gameplayModiferParamsList = gameplayModifiersSO.CreateModifierParamsList(gameplayModifiers); PlayerSpecificSettings playerSettings = gameplayCoreSceneSetupData.playerSpecificSettings; PracticeSettings practiceSettings = gameplayCoreSceneSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } int beatmapObjectId = 0; var beatmapObjectsData = diff.beatmapData.beatmapObjectsData; // Generate NoteData to id mappings for backwards compatiblity with <1.12.1 noteToIdMapping = new NoteData[beatmapObjectsData.Count(obj => obj is NoteData)]; lastNoteId = 0; foreach (BeatmapObjectData beatmapObjectData in beatmapObjectsData) { if (beatmapObjectData is NoteData noteData) { noteToIdMapping[beatmapObjectId++] = noteData; } } gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.levelAuthorName = level.levelAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; gameStatus.noteJumpStartBeatOffset = diff.noteJumpStartBeatOffset; // 13 is "custom_level_" and 40 is the magic number for the length of the SHA-1 hash gameStatus.songHash = Regex.IsMatch(level.levelID, "^custom_level_[0-9A-F]{40}", RegexOptions.IgnoreCase) && !level.levelID.EndsWith(" WIP") ? level.levelID.Substring(13, 40) : null; gameStatus.levelId = level.levelID; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.beatmapLevelData.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.difficultyEnum = Enum.GetName(typeof(BeatmapDifficulty), diff.difficulty); gameStatus.characteristic = diff.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; gameStatus.notesCount = diff.beatmapData.cuttableNotesCount; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.environmentName = level.environmentInfo.sceneInfo.sceneName; ColorScheme colorScheme = gameplayCoreSceneSetupData.colorScheme ?? new ColorScheme(gameplayCoreSceneSetupData.environmentInfo.colorScheme); gameStatus.colorSaberA = colorScheme.saberAColor; gameStatus.colorSaberB = colorScheme.saberBColor; gameStatus.colorEnvironment0 = colorScheme.environmentColor0; gameStatus.colorEnvironment1 = colorScheme.environmentColor1; if (colorScheme.supportsEnvironmentColorBoost) { gameStatus.colorEnvironmentBoost0 = colorScheme.environmentColor0Boost; gameStatus.colorEnvironmentBoost1 = colorScheme.environmentColor1Boost; } gameStatus.colorObstacle = colorScheme.obstaclesColor; try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- // Modified to correctly handle texture atlases. Fixes #82. var active = RenderTexture.active; var sprite = await level.GetCoverImageAsync(CancellationToken.None); var texture = sprite.texture; var temporary = RenderTexture.GetTemporary(texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var spriteRect = sprite.rect; var uv = sprite.uv[0]; var cover = new Texture2D((int)spriteRect.width, (int)spriteRect.height); // Unity sucks. The coordinates of the sprite on its texture atlas are only accessible through the Sprite.uv property since rect always returns `x=0,y=0`, so we need to convert them back into texture space. cover.ReadPixels(new Rect( uv.x * texture.width, texture.height - uv.y * texture.height, spriteRect.width, spriteRect.height ), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String(ImageConversion.EncodeToPNG(cover)); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); UpdateModMultiplier(); gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFailOn0Energy; gameStatus.modBatteryEnergy = gameplayModifiers.energyType == GameplayModifiers.EnergyType.Battery; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modNoArrows = gameplayModifiers.noArrows; gameStatus.modGhostNotes = gameplayModifiers.ghostNotes; gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; gameStatus.modFastNotes = gameplayModifiers.fastNotes; gameStatus.modSmallNotes = gameplayModifiers.smallCubes; gameStatus.modProMode = gameplayModifiers.proMode; gameStatus.modZenMode = gameplayModifiers.zenMode; var environmentEffectsFilterPreset = diff.difficulty == BeatmapDifficulty.ExpertPlus ? playerSettings.environmentEffectsFilterExpertPlusPreset : playerSettings.environmentEffectsFilterDefaultPreset; // Backwards compatibility for <1.13.4 gameStatus.staticLights = environmentEffectsFilterPreset != EnvironmentEffectsFilterPreset.AllEffects; gameStatus.leftHanded = playerSettings.leftHanded; gameStatus.playerHeight = playerSettings.playerHeight; gameStatus.sfxVolume = playerSettings.sfxVolume; gameStatus.reduceDebris = playerSettings.reduceDebris; gameStatus.noHUD = playerSettings.noTextsAndHuds; gameStatus.advancedHUD = playerSettings.advancedHud; gameStatus.autoRestart = playerSettings.autoRestart; gameStatus.saberTrailIntensity = playerSettings.saberTrailIntensity; gameStatus.environmentEffects = environmentEffectsFilterPreset.ToString(); gameStatus.hideNoteSpawningEffect = playerSettings.hideNoteSpawnEffect; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); }
private void CleanUpSong() { statusManager.gameStatus.ResetMapInfo(); statusManager.gameStatus.ResetPerformance(); noteControllerMapping.Clear(); // Release references for AfterCutScoreBuffers that don't resolve due to player leaving the map before finishing. foreach (var noteCutItem in noteCutMapping) { // CutScoreBuffers are pooled. Remove the event listener just in case it never fires the event. noteCutItem.Key.didFinishEvent.Remove(this); } noteCutMapping.Clear(); // Clear note id mappings. noteToIdMapping = null; if (pauseController != null) { pauseController.didPauseEvent -= OnGamePause; pauseController.didResumeEvent -= OnGameResume; pauseController = null; } if (scoreController != null) { scoreController.noteWasCutEvent -= OnNoteWasCut; scoreController.noteWasMissedEvent -= OnNoteWasMissed; scoreController.scoreDidChangeEvent -= OnScoreDidChange; scoreController.comboDidChangeEvent -= OnComboDidChange; scoreController.multiplierDidChangeEvent -= OnMultiplierDidChange; scoreController = null; } if (beatmapObjectManager != null) { beatmapObjectManager.noteWasSpawnedEvent -= OnNoteWasSpawned; beatmapObjectManager = null; } if (gameplayManager != null) { if (gameplayManager is ILevelEndActions levelEndActions) { // event Action levelFailedEvent; levelEndActions.levelFailedEvent -= OnLevelFailed; } gameplayManager = null; } if (beatmapObjectCallbackController != null) { beatmapObjectCallbackController.beatmapEventDidTriggerEvent -= OnBeatmapEventDidTrigger; beatmapObjectCallbackController = null; } if (gameplayModifiersSO != null) { gameplayModifiersSO = null; } if (audioTimeSyncController != null) { audioTimeSyncController = null; } if (playerHeadAndObstacleInteraction != null) { playerHeadAndObstacleInteraction = null; } if (gameSongController != null) { gameSongController.songDidFinishEvent -= OnLevelFinished; gameSongController = null; } if (gameEnergyCounter != null) { gameEnergyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0Event; gameEnergyCounter = null; } if (gameplayCoreSceneSetupData != null) { gameplayCoreSceneSetupData = null; } if (gameplayModifiers != null) { gameplayModifiers = null; } if (gameplayModiferParamsList != null) { gameplayModiferParamsList = null; } }
private void OnSceneLoaded(Scene newScene, LoadSceneMode mode) { var gameStatus = statusManager.gameStatus; gameStatus.scene = newScene.name; if (newScene.name == "Menu") { // Menu headInObstacle = false; // TODO: get the current song, mode and mods while in menu gameStatus.ResetMapInfo(); gameStatus.ResetPerformance(); statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "menu"); } else if (newScene.name == "StandardLevel") { // In game mainSetupData = Resources.FindObjectsOfTypeAll <MainGameSceneSetupData>().FirstOrDefault(); if (mainSetupData == null) { Console.WriteLine("[HTTP Status] Couldn't find MainGameSceneSetupData"); return; } gamePauseManager = Resources.FindObjectsOfTypeAll <GamePauseManager>().FirstOrDefault(); if (gamePauseManager == null) { Console.WriteLine("[HTTP Status] Couldn't find GamePauseManager"); return; } scoreController = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); if (scoreController == null) { Console.WriteLine("[HTTP Status] Couldn't find ScoreController"); return; } gameplayManager = Resources.FindObjectsOfTypeAll <GameplayManager>().FirstOrDefault(); if (gameplayManager == null) { Console.WriteLine("[HTTP Status] Couldn't find GameplayManager"); return; } beatmapObjectCallbackController = Resources.FindObjectsOfTypeAll <BeatmapObjectCallbackController>().FirstOrDefault(); if (beatmapObjectCallbackController == null) { Console.WriteLine("[HTTP Status] Couldn't find BeatmapObjectCallbackController"); return; } GameSongController gameSongController = (GameSongController)gameSongControllerField.GetValue(gameplayManager); audioTimeSyncController = (AudioTimeSyncController)audioTimeSyncControllerField.GetValue(gameSongController); playerHeadAndObstacleInteraction = (PlayerHeadAndObstacleInteraction)playerHeadAndObstacleInteractionField.GetValue(scoreController); // Register event listeners // private GameEvent GamePauseManager#_gameDidPauseSignal AddSubscriber(gamePauseManager, "_gameDidPauseSignal", OnGamePause); // private GameEvent GamePauseManager#_gameDidResumeSignal AddSubscriber(gamePauseManager, "_gameDidResumeSignal", OnGameResume); // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // private GameEvent GameplayManager#_levelFinishedSignal AddSubscriber(gameplayManager, "_levelFinishedSignal", OnLevelFinished); // private GameEvent GameplayManager#_levelFailedSignal AddSubscriber(gameplayManager, "_levelFailedSignal", OnLevelFailed); // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; var diff = mainSetupData.difficultyLevel; var level = diff.level; gameStatus.mode = mainSetupData.gameplayMode.ToString(); gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f); gameStatus.length = (long)(level.audioClip.length * 1000f); gameStatus.start = GetCurrentTime(); gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.notesCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.maxScore = ScoreController.MaxScoreForNumberOfNotes(diff.beatmapData.notesCount); try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- var texture = level.coverImage.texture; var active = RenderTexture.active; var temporary = RenderTexture.GetTemporary( texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear ); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var cover = new Texture2D(texture.width, texture.height); cover.ReadPixels(new Rect(0, 0, temporary.width, temporary.height), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String( ImageConversion.EncodeToPNG(cover) ); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); // TODO: obstaclesOption can be All, FullHeightOnly or None. Reflect that? gameStatus.modObstacles = mainSetupData.gameplayOptions.obstaclesOption.ToString(); gameStatus.modNoEnergy = mainSetupData.gameplayOptions.noEnergy; gameStatus.modMirror = mainSetupData.gameplayOptions.mirror; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); } else { statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "scene"); } }
private void AddEvents() { leftEventManager = leftSaber?.GetComponent <EventManager>(); if (!leftEventManager) { leftEventManager = leftSaber.AddComponent <EventManager>(); } rightEventManager = rightSaber?.GetComponent <EventManager>(); if (!rightEventManager) { rightEventManager = rightSaber.AddComponent <EventManager>(); } if (leftEventManager?.OnLevelStart == null || rightEventManager?.OnLevelStart == null) { return; } leftEventManager.OnLevelStart.Invoke(); rightEventManager.OnLevelStart.Invoke(); try { beatmapObjectManager = Resources.FindObjectsOfTypeAll <BeatmapObjectManager>().FirstOrDefault(); if (beatmapObjectManager) { beatmapObjectManager.noteWasCutEvent += SliceCallBack; beatmapObjectManager.noteWasMissedEvent += NoteMissCallBack; } else { Logger.log.Warn($"Failed to locate a suitable '{nameof(BeatmapObjectManager)}'."); } scoreController = Resources.FindObjectsOfTypeAll <ScoreController>().FirstOrDefault(); if (scoreController) { scoreController.multiplierDidChangeEvent += MultiplierCallBack; scoreController.comboDidChangeEvent += ComboChangeEvent; } else { Logger.log.Warn($"Failed to locate a suitable '{nameof(ScoreController)}'."); } saberCollisionManager = Resources.FindObjectsOfTypeAll <ObstacleSaberSparkleEffectManager>().FirstOrDefault(); if (saberCollisionManager) { saberCollisionManager.sparkleEffectDidStartEvent += SaberStartCollide; saberCollisionManager.sparkleEffectDidEndEvent += SaberEndCollide; } else { Logger.log.Warn($"Failed to locate a suitable '{nameof(ObstacleSaberSparkleEffectManager)}'."); } gameEnergyCounter = Resources.FindObjectsOfTypeAll <GameEnergyCounter>().FirstOrDefault(); if (gameEnergyCounter) { gameEnergyCounter.gameEnergyDidReach0Event += FailLevelCallBack; } else { Logger.log.Warn($"Failed to locate a suitable '{nameof(GameEnergyCounter)}'."); } beatmapCallback = Resources.FindObjectsOfTypeAll <BeatmapObjectCallbackController>().FirstOrDefault(); if (beatmapCallback) { beatmapCallback.beatmapEventDidTriggerEvent += LightEventCallBack; } else { Logger.log.Warn($"Failed to locate a suitable '{nameof(BeatmapObjectCallbackController)}'."); } playerHeadAndObstacleInteraction = Resources.FindObjectsOfTypeAll <PlayerHeadAndObstacleInteraction>().FirstOrDefault(); if (!playerHeadAndObstacleInteraction) { Logger.log.Warn($"Failed to locate a suitable '{nameof(PlayerHeadAndObstacleInteraction)}'."); } } catch (Exception ex) { Logger.log.Error(ex); throw; } try { float LastTime = 0.0f; LevelData levelData = BS_Utils.Plugin.LevelData; BeatmapData beatmapData = levelData.GameplayCoreSceneSetupData.difficultyBeatmap.beatmapData; IEnumerable <BeatmapLineData> beatmapLinesData = beatmapData.beatmapLinesData; foreach (BeatmapLineData beatMapLineData in beatmapLinesData) { IList <BeatmapObjectData> beatmapObjectsData = beatMapLineData.beatmapObjectsData; for (int i = beatmapObjectsData.Count - 1; i >= 0; i--) { BeatmapObjectData beatmapObjectData = beatmapObjectsData[i]; if (beatmapObjectData.beatmapObjectType == BeatmapObjectType.Note && ((NoteData)beatmapObjectData).noteType != NoteType.Bomb) { if (beatmapObjectData.time > LastTime) { lastNoteId = beatmapObjectData.id; LastTime = beatmapObjectData.time; } break; } } } } catch (Exception ex) { Logger.log.Error(ex); throw; } }
public async void HandleSongStart() { GameStatus gameStatus = statusManager.gameStatus; // Check for multiplayer early to abort if needed: gameplay controllers don't exist in multiplayer until later multiplayerSessionManager = FindFirstOrDefaultOptional <MultiplayerSessionManager>(); multiplayerController = FindFirstOrDefaultOptional <MultiplayerController>(); if (multiplayerSessionManager && multiplayerController) { Plugin.log.Debug("Multiplayer Level loaded"); // public event Action<DisconnectedReason> MultiplayerSessionManager#disconnectedEvent; multiplayerSessionManager.disconnectedEvent += OnMultiplayerDisconnected; // public event Action<State> MultiplayerController#stateChangedEvent; multiplayerController.stateChangedEvent += OnMultiplayerStateChanged; // Do nothing until the next state change to Gameplay. if (multiplayerController.state != MultiplayerController.State.Gameplay) { return; } multiplayerLocalActivePlayerFacade = FindFirstOrDefaultOptional <MultiplayerLocalActivePlayerFacade>(); if (multiplayerLocalActivePlayerFacade != null) { multiplayerLocalActivePlayerFacade.playerDidFinishEvent += OnMultiplayerLevelFinished; } } else if (!doDelayedSongStart) { doDelayedSongStart = true; return; } // `wants_to_play_next_level` is set for players who don't want to play the song aka want to spectate aka are not "active". `isSpectating` is apparently not spectating. gameStatus.scene = multiplayerSessionManager.isSpectating || !multiplayerSessionManager.LocalPlayerHasState(NetworkConstants.wantsToPlayNextLevel) ? "Spectator" : "Song"; gameStatus.multiplayer = multiplayerSessionManager.isConnectingOrConnected; pauseController = FindFirstOrDefaultOptional <PauseController>(); scoreController = FindFirstOrDefault <ScoreController>(); gameplayManager = FindFirstOrDefaultOptional <StandardLevelGameplayManager>() as MonoBehaviour ?? FindFirstOrDefaultOptional <MissionLevelGameplayManager>(); beatmapObjectCallbackController = FindFirstOrDefault <BeatmapObjectCallbackController>(); gameplayModifiersSO = FindFirstOrDefault <GameplayModifiersModelSO>(); audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>(); playerHeadAndObstacleInteraction = (PlayerHeadAndObstacleInteraction)scoreControllerHeadAndObstacleInteractionField.GetValue(scoreController); gameSongController = FindFirstOrDefault <GameSongController>(); gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>(); if (multiplayerController) { // NOOP } else if (gameplayManager is StandardLevelGameplayManager) { Plugin.log.Debug("Standard Level loaded"); } else if (gameplayManager is MissionLevelGameplayManager) { Plugin.log.Debug("Mission Level loaded"); } gameplayCoreSceneSetupData = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData; // Register event listeners // PauseController doesn't exist in multiplayer if (pauseController != null) { // public event Action PauseController#didPauseEvent; pauseController.didPauseEvent += OnGamePause; // public event Action PauseController#didResumeEvent; pauseController.didResumeEvent += OnGameResume; } // public ScoreController#noteWasCutEvent<NoteData, NoteCutInfo, int multiplier> // called after AfterCutScoreBuffer is created scoreController.noteWasCutEvent += OnNoteWasCut; // public ScoreController#noteWasMissedEvent<NoteData, int multiplier> scoreController.noteWasMissedEvent += OnNoteWasMissed; // public ScoreController#scoreDidChangeEvent<int, int> // score scoreController.scoreDidChangeEvent += OnScoreDidChange; // public ScoreController#comboDidChangeEvent<int> // combo scoreController.comboDidChangeEvent += OnComboDidChange; // public ScoreController#multiplierDidChangeEvent<int, float> // multiplier, progress [0..1] scoreController.multiplierDidChangeEvent += OnMultiplierDidChange; // public event Action<BeatmapEventData> BeatmapObjectCallbackController#beatmapEventDidTriggerEvent beatmapObjectCallbackController.beatmapEventDidTriggerEvent += OnBeatmapEventDidTrigger; // public event Action GameSongController#songDidFinishEvent; gameSongController.songDidFinishEvent += OnLevelFinished; // public event Action GameEnergyCounter#gameEnergyDidReach0Event; gameEnergyCounter.gameEnergyDidReach0Event += OnEnergyDidReach0Event; if (gameplayManager is ILevelEndActions levelEndActions) { // event Action levelFailedEvent; levelEndActions.levelFailedEvent += OnLevelFailed; } IDifficultyBeatmap diff = gameplayCoreSceneSetupData.difficultyBeatmap; IBeatmapLevel level = diff.level; gameStatus.partyMode = Gamemode.IsPartyActive; gameStatus.mode = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData.difficultyBeatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; gameplayModifiers = gameplayCoreSceneSetupData.gameplayModifiers; PlayerSpecificSettings playerSettings = gameplayCoreSceneSetupData.playerSpecificSettings; PracticeSettings practiceSettings = gameplayCoreSceneSetupData.practiceSettings; float songSpeedMul = gameplayModifiers.songSpeedMul; if (practiceSettings != null) { songSpeedMul = practiceSettings.songSpeedMul; } // Generate NoteData to id mappings for backwards compatiblity with <1.12.1 noteToIdMapping = new NoteData[diff.beatmapData.cuttableNotesType + diff.beatmapData.bombsCount]; lastNoteId = 0; int beatmapObjectId = 0; var beatmapObjectsData = diff.beatmapData.beatmapObjectsData; foreach (BeatmapObjectData beatmapObjectData in beatmapObjectsData) { if (beatmapObjectData is NoteData noteData) { noteToIdMapping[beatmapObjectId++] = noteData; } } gameStatus.songName = level.songName; gameStatus.songSubName = level.songSubName; gameStatus.songAuthorName = level.songAuthorName; gameStatus.levelAuthorName = level.levelAuthorName; gameStatus.songBPM = level.beatsPerMinute; gameStatus.noteJumpSpeed = diff.noteJumpMovementSpeed; // 13 is "custom_level_" and 40 is the magic number for the length of the SHA-1 hash gameStatus.songHash = level.levelID.StartsWith("custom_level_") && !level.levelID.EndsWith(" WIP") ? level.levelID.Substring(13, 40) : null; gameStatus.levelId = level.levelID; gameStatus.songTimeOffset = (long)(level.songTimeOffset * 1000f / songSpeedMul); gameStatus.length = (long)(level.beatmapLevelData.audioClip.length * 1000f / songSpeedMul); gameStatus.start = GetCurrentTime() - (long)(audioTimeSyncController.songTime * 1000f / songSpeedMul); if (practiceSettings != null) { gameStatus.start -= (long)(practiceSettings.startSongTime * 1000f / songSpeedMul); } gameStatus.paused = 0; gameStatus.difficulty = diff.difficulty.Name(); gameStatus.notesCount = diff.beatmapData.cuttableNotesType; gameStatus.bombsCount = diff.beatmapData.bombsCount; gameStatus.obstaclesCount = diff.beatmapData.obstaclesCount; gameStatus.environmentName = level.environmentInfo.sceneInfo.sceneName; try { // From https://support.unity3d.com/hc/en-us/articles/206486626-How-can-I-get-pixels-from-unreadable-textures- var texture = (await level.GetCoverImageAsync(CancellationToken.None)).texture; var active = RenderTexture.active; var temporary = RenderTexture.GetTemporary( texture.width, texture.height, 0, RenderTextureFormat.Default, RenderTextureReadWrite.Linear ); Graphics.Blit(texture, temporary); RenderTexture.active = temporary; var cover = new Texture2D(texture.width, texture.height); cover.ReadPixels(new Rect(0, 0, temporary.width, temporary.height), 0, 0); cover.Apply(); RenderTexture.active = active; RenderTexture.ReleaseTemporary(temporary); gameStatus.songCover = System.Convert.ToBase64String( ImageConversion.EncodeToPNG(cover) ); } catch { gameStatus.songCover = null; } gameStatus.ResetPerformance(); UpdateModMultiplier(); gameStatus.songSpeedMultiplier = songSpeedMul; gameStatus.batteryLives = gameEnergyCounter.batteryLives; gameStatus.modObstacles = gameplayModifiers.enabledObstacleType.ToString(); gameStatus.modInstaFail = gameplayModifiers.instaFail; gameStatus.modNoFail = gameplayModifiers.noFailOn0Energy; gameStatus.modBatteryEnergy = gameplayModifiers.energyType == GameplayModifiers.EnergyType.Battery; gameStatus.modDisappearingArrows = gameplayModifiers.disappearingArrows; gameStatus.modNoBombs = gameplayModifiers.noBombs; gameStatus.modSongSpeed = gameplayModifiers.songSpeed.ToString(); gameStatus.modNoArrows = gameplayModifiers.noArrows; gameStatus.modGhostNotes = gameplayModifiers.ghostNotes; gameStatus.modFailOnSaberClash = gameplayModifiers.failOnSaberClash; gameStatus.modStrictAngles = gameplayModifiers.strictAngles; gameStatus.modFastNotes = gameplayModifiers.fastNotes; gameStatus.staticLights = playerSettings.staticLights; gameStatus.leftHanded = playerSettings.leftHanded; gameStatus.playerHeight = playerSettings.playerHeight; gameStatus.sfxVolume = playerSettings.sfxVolume; gameStatus.reduceDebris = playerSettings.reduceDebris; gameStatus.noHUD = playerSettings.noTextsAndHuds; gameStatus.advancedHUD = playerSettings.advancedHud; gameStatus.autoRestart = playerSettings.autoRestart; statusManager.EmitStatusUpdate(ChangedProperties.AllButNoteCut, "songStart"); }