//private BeatmapObjectCallbackController beatmapObjectCallbackController;

        public void SceneManagerOnActiveSceneChanged(Scene oldScene, Scene newScene)
        {
            if (newScene.name == "GameCore")
            {
                gameStatus = new GameStatus();

                levelSceneSetupData = FindFirstOrDefault <StandardLevelSceneSetupDataSO>();
                //gamePauseManager = FindFirstOrDefault<GamePauseManager>();
                scoreController         = FindFirstOrDefault <ScoreController>();
                gameplayModifiersSO     = FindFirstOrDefault <GameplayModifiersModelSO>();
                audioTimeSyncController = FindFirstOrDefault <AudioTimeSyncController>();
                //playerHeadAndObstacleInteraction = FindFirstOrDefault<PlayerHeadAndObstacleInteraction>();
                gameEnergyCounter = FindFirstOrDefault <GameEnergyCounter>();
                gameplayManager   = FindFirstOrDefault <StandardLevelGameplayManager>();
                //beatmapObjectCallbackController = FindFirstOrDefault<BeatmapObjectCallbackController>();

                // 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;

                IDifficultyBeatmap diff  = levelSceneSetupData.difficultyBeatmap;
                IBeatmapLevel      level = diff.level;

                GameplayModifiers      gameplayModifiers = levelSceneSetupData.gameplayCoreSetupData.gameplayModifiers;
                PlayerSpecificSettings playerSettings    = levelSceneSetupData.gameplayCoreSetupData.playerSpecificSettings;
                PracticeSettings       practiceSettings  = levelSceneSetupData.gameplayCoreSetupData.practiceSettings;

                float songSpeedMul = gameplayModifiers.songSpeedMul;
                if (practiceSettings != null)
                {
                    songSpeedMul = practiceSettings.songSpeedMul;
                }
                float modifierMultiplier = gameplayModifiersSO.GetTotalMultiplier(gameplayModifiers);

                var songInfo = FindLevelInfancyWay(levelSceneSetupData.difficultyBeatmap.level.levelID);


                gameStatus.songHash        = level.levelID.Substring(0, Math.Max(0, level.levelID.IndexOf('∎')));
                gameStatus.songBeatSaverID = songInfo == null ? null : ParseIdFromSongPath(songInfo);
                gameStatus.songFilePath    = songInfo?.path;
                gameStatus.songName        = level.songName;
                gameStatus.songSubName     = level.songSubName;
                gameStatus.songAuthorName  = level.songAuthorName;
                gameStatus.songBPM         = level.beatsPerMinute;
                gameStatus.noteJumpSpeed   = diff.noteJumpMovementSpeed;
                gameStatus.songTimeOffset  = (long)(level.songTimeOffset * 1000f / songSpeedMul);
                gameStatus.length          = (long)(level.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.maxScore         = ScoreController.GetScoreForGameplayModifiersScoreMultiplier(ScoreController.MaxScoreForNumberOfNotes(diff.beatmapData.notesCount), modifierMultiplier);
                gameStatus.maxPossibleScore = ScoreController.MaxScoreForNumberOfNotes(diff.beatmapData.notesCount);
                gameStatus.maxRank          = RankModel.MaxRankForGameplayModifiers(gameplayModifiers, gameplayModifiersSO).ToString();

                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.modFailOnSaberClash   = gameplayModifiers.failOnSaberClash;
                gameStatus.modStrictAngles       = gameplayModifiers.strictAngles;
            }
        }
        private void SaveScore(GameStatus gameStatus)
        {
            try
            {
                var songScores = localProfilesData.SongScores;
                var song       = songScores.ContainsKey(gameStatus.songHash) ? songScores[gameStatus.songHash] : null;
                if (song == null)
                {
                    song = new SongInfo()
                    {
                        Hash        = gameStatus.songHash,
                        BeatSaverID = gameStatus.songBeatSaverID,
                        FilePath    = gameStatus.songFilePath,
                        Name        = gameStatus.songName,
                        SubName     = gameStatus.songSubName,
                        AuthorName  = gameStatus.songAuthorName,
                        BPM         = gameStatus.songBPM,
                        Length      = gameStatus.length
                    };
                    songScores.Add(song.Hash, song);
                }

                localProfilesData.lastSong = song;

                var difficulty = song.Difficulties.FirstOrDefault(x => x.Difficulty == gameStatus.difficulty);
                if (difficulty == null)
                {
                    difficulty = new SongDifficulty()
                    {
                        Difficulty     = gameStatus.difficulty,
                        BombsCount     = gameStatus.bombsCount,
                        MaxRank        = gameStatus.maxRank,
                        MaxScore       = gameStatus.maxScore,
                        NoteJumpSpeed  = gameStatus.noteJumpSpeed,
                        NotesCount     = gameStatus.notesCount,
                        ObstaclesCount = gameStatus.obstaclesCount
                    };
                    song.Difficulties.Add(difficulty);
                }

                localProfilesData.lastDiff = difficulty;

                var profile = difficulty.Profiles.FirstOrDefault(x => x.Name == localProfilesData.CurrentProfile);
                if (profile == null)
                {
                    profile = new Profile()
                    {
                        Name = localProfilesData.CurrentProfile
                    };
                    difficulty.Profiles.Add(profile);
                }

                localProfilesData.lastProfile = profile;


                //var scores = profile.Scores.ContainsKey(gameStatus.songHash) ? profile.Scores[gameStatus.songHash] : null;
                //if (scores == null)
                //{
                //    profile.Scores.Add(gameStatus.songHash, new List<Score>());
                //}

                var score = new Score()
                {
                    score            = gameStatus.score,
                    maxPossibleScore = gameStatus.currentMaxScore,
                    rank             = gameStatus.rank,
                    passedNotes      = gameStatus.passedNotes,
                    hitNotes         = gameStatus.hitNotes,
                    missedNotes      = gameStatus.missedNotes,
                    passedBombs      = gameStatus.passedBombs,
                    hitBombs         = gameStatus.hitBombs,
                    maxCombo         = gameStatus.maxCombo,
                    timePlayed       = GameStatusTracker.GetCurrentTime() - gameStatus.start,
                    timestamp        = (int)(GameStatusTracker.GetCurrentTime() / 1000),

                    modifierMultiplier = gameStatus.modifierMultiplier,

                    batteryLives          = gameStatus.batteryLives,
                    modObstacles          = gameStatus.modObstacles,
                    modInstaFail          = gameStatus.modInstaFail,
                    modNoFail             = gameStatus.modNoFail,
                    modBatteryEnergy      = gameStatus.modBatteryEnergy,
                    modDisappearingArrows = gameStatus.modDisappearingArrows,
                    modNoBombs            = gameStatus.modNoBombs,
                    modSongSpeed          = gameStatus.modSongSpeed,
                    modFailOnSaberClash   = gameStatus.modFailOnSaberClash,
                    modStrictAngles       = gameStatus.modStrictAngles
                };

                profile.Scores.Add(score);

                localProfilesData.lastScore = score;


                //var js = Newtonsoft.Json.JsonConvert.SerializeObject(gameStatus, Newtonsoft.Json.Formatting.Indented);
                //File.WriteAllText(Path.Combine(ScoreDirPath, "score" + DateTime.Now.ToString("yyyyMMddHHmmss") + ".txt"), js);
                var js = Newtonsoft.Json.JsonConvert.SerializeObject(song, Newtonsoft.Json.Formatting.Indented);
                File.WriteAllText(Path.Combine(localProfilesData.ScoreDirPath, song.Hash + ".json"), js);
            }catch (Exception ex)
            {
                Plugin.Log("ERROR SAVING SCORE!! " + ex);
            }
        }