diff --git a/SongPlayHistory/Installers/ScoreTrackerInstaller.cs b/SongPlayHistory/Installers/ScoreTrackerInstaller.cs index 4f366e0..360ece1 100644 --- a/SongPlayHistory/Installers/ScoreTrackerInstaller.cs +++ b/SongPlayHistory/Installers/ScoreTrackerInstaller.cs @@ -8,7 +8,7 @@ public class ScoreTrackerInstaller : Installer public override void InstallBindings() { Plugin.Log.Warn("Binding ScoreTracker"); - Container.BindInterfacesTo().AsSingle().NonLazy(); + Container.BindInterfacesTo().AsSingle(); } } } \ No newline at end of file diff --git a/SongPlayHistory/RecordsManager.cs b/SongPlayHistory/RecordsManager.cs index 541590e..f4998c8 100644 --- a/SongPlayHistory/RecordsManager.cs +++ b/SongPlayHistory/RecordsManager.cs @@ -105,10 +105,8 @@ private void OnGameSceneLoaded() var practiceSettings = BS_Utils.Plugin.LevelData.GameplayCoreSceneSetupData?.practiceSettings; _isPractice = practiceSettings != null; _isReplay = Utils.Utils.IsInReplay(); - ScoreTracker.MaxRawScore = null; - ScoreTracker.RawScore = null; - ScoreTracker.MultipliedScore = null; ScoreTracker.EnergyDidReach0 = false; + ScoreTracker.FailScoreRecord = null; } private void OnLevelFinished(object scene, LevelFinishedEventArgs eventArgs) @@ -125,11 +123,13 @@ private void OnLevelFinished(object scene, LevelFinishedEventArgs eventArgs) } var result = ((LevelFinishedWithResultsEventArgs)eventArgs).CompletionResults; + var energyDidReach0 = ScoreTracker.EnergyDidReach0; + var failRecord = ScoreTracker.FailScoreRecord; if (eventArgs.LevelType == LevelType.Multiplayer) { var beatmap = ((MultiplayerLevelScenesTransitionSetupDataSO)scene).difficultyBeatmap; - SaveRecord(beatmap, result, true); + SaveRecord(beatmap, result, true, energyDidReach0, failRecord); } else { @@ -140,7 +140,7 @@ private void OnLevelFinished(object scene, LevelFinishedEventArgs eventArgs) return; } var beatmap = ((StandardLevelScenesTransitionSetupDataSO)scene).difficultyBeatmap; - SaveRecord(beatmap, result, false); + SaveRecord(beatmap, result, false, energyDidReach0, failRecord); } } @@ -161,7 +161,7 @@ public IList GetRecords(IDifficultyBeatmap beatmap) return new List(); } - private void SaveRecord(IDifficultyBeatmap? beatmap, LevelCompletionResults? result, bool isMultiplayer) + private void SaveRecord(IDifficultyBeatmap? beatmap, LevelCompletionResults? result, bool isMultiplayer, bool energyDidReach0, ScoreRecord? failRecord) { if (beatmap == null || result == null) { @@ -183,46 +183,57 @@ private void SaveRecord(IDifficultyBeatmap? beatmap, LevelCompletionResults? res // We now keep failed records. var cleared = result.levelEndStateType == LevelCompletionResults.LevelEndStateType.Cleared; - var softFailed = ScoreTracker.EnergyDidReach0; - var submissionDisabled = ScoreSubmission.WasDisabled || ScoreSubmission.Disabled || ScoreSubmission.ProlongedDisabled; - // If submissionDisabled = true, we assume custom gameplay modifiers are applied. - var param = ParamHelper.ModsToParam(result.gameplayModifiers, softFailed); + var noFailEnabled = result.gameplayModifiers.noFailOn0Energy; + + _logger.Debug($"Cleared: {cleared}, NoFail: {noFailEnabled}, SoftFailed: {energyDidReach0}, FailRecord: {failRecord}"); + + var param = ParamHelper.ModsToParam(result.gameplayModifiers, energyDidReach0); param |= submissionDisabled ? Param.SubmissionDisabled : 0; param |= isMultiplayer ? Param.Multiplayer : 0; - + var time = DateTimeOffset.Now.ToUnixTimeMilliseconds(); Record record; - if (cleared && softFailed && ScoreTracker.RawScore != null && ScoreTracker.MultipliedScore != null) + if (cleared && energyDidReach0 && failRecord != null) { // use our tracked values at the time of soft fail record = new Record { - Date = DateTimeOffset.Now.ToUnixTimeMilliseconds(), - ModifiedScore = ScoreTracker.RawScore.Value, - RawScore = ScoreTracker.MultipliedScore.Value, - LastNote = ScoreTracker.NotesPassed, + Date = time, + ModifiedScore = failRecord.Value.RawScore, + RawScore = failRecord.Value.ModifiedScore, + LastNote = failRecord.Value.NotesPassed, + Param = (int) param, + MaxRawScore = failRecord.Value.MaxRawScore + }; + } + else if (!cleared && noFailEnabled && energyDidReach0 && failRecord != null) + { + // No fail is enabled, but level still failed (for example, thr FailButton mod) + record = new Record + { + Date = time, + ModifiedScore = failRecord.Value.RawScore, + RawScore = failRecord.Value.ModifiedScore, + LastNote = failRecord.Value.NotesPassed, Param = (int) param, - MaxRawScore = ScoreTracker.MaxRawScore + MaxRawScore = failRecord.Value.MaxRawScore }; } else { record = new Record { - Date = DateTimeOffset.Now.ToUnixTimeMilliseconds(), + Date = time, ModifiedScore = result.modifiedScore, RawScore = result.multipliedScore, LastNote = cleared ? -1 : result.goodCutsCount + result.badCutsCount + result.missedCount, Param = (int) param, - MaxRawScore = cleared ? null : ScoreTracker.MaxRawScore + MaxRawScore = cleared ? null : failRecord?.MaxRawScore }; } - - - - _logger.Info($"Saving result."); - _logger.Debug($"Record: {record.ToShortString()}"); + + _logger.Info($"Saving result. Record: {record.ToShortString()}"); var beatmapCharacteristicName = beatmap.parentDifficultyBeatmapSet.beatmapCharacteristic.serializedName; var difficulty = $"{beatmap.level.levelID}___{(int)beatmap.difficulty}___{beatmapCharacteristicName}"; diff --git a/SongPlayHistory/Utils/ScoreTracker.cs b/SongPlayHistory/Utils/ScoreTracker.cs index 177c49f..b21c16a 100644 --- a/SongPlayHistory/Utils/ScoreTracker.cs +++ b/SongPlayHistory/Utils/ScoreTracker.cs @@ -6,93 +6,112 @@ namespace SongPlayHistory.Utils { public class ScoreTracker : IInitializable, IDisposable { - public static int? MaxRawScore { get; internal set; } = null; - public static int? RawScore { get; internal set; } = null; + private int _maxRawScore; + private int _rawScore; + private int _modifiedScore; + private int _notesPassed; - public static int? MultipliedScore { get; internal set; } = null; public static bool EnergyDidReach0 { get; internal set; } = false; - public static int NotesPassed { get; private set; } = 0; + + /** + * Score record of when the energy first reached 0 + */ + public static ScoreRecord? FailScoreRecord { get; internal set; } = null; - [InjectOptional] - private readonly IScoreController? _scoreController = null; + [Inject] + private readonly IScoreController _scoreController = null!; - [InjectOptional] - private readonly IGameEnergyCounter? _energyCounter = null; + [Inject] + private readonly IGameEnergyCounter _energyCounter = null!; - [InjectOptional] - private readonly BeatmapObjectManager? _beatmapObjectManager = null; + [Inject] + private readonly BeatmapObjectManager _beatmapObjectManager = null!; [Inject] private readonly SiraLog _logger = null!; public void Initialize() { - MaxRawScore = null; - RawScore = null; - MultipliedScore = null; + _maxRawScore = 0; + _rawScore = 0; + _modifiedScore = 0; EnergyDidReach0 = false; - NotesPassed = 0; - if (_scoreController != null && _energyCounter != null && _beatmapObjectManager != null) - { - _energyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0; - _energyCounter.gameEnergyDidReach0Event += OnEnergyDidReach0; - _scoreController.scoringForNoteFinishedEvent -= OnScoreChanged; - _scoreController.scoringForNoteFinishedEvent += OnScoreChanged; - _beatmapObjectManager.noteWasCutEvent -= OnNoteCut; - _beatmapObjectManager.noteWasCutEvent += OnNoteCut; - _beatmapObjectManager.noteWasMissedEvent -= OnNoteMiss; - _beatmapObjectManager.noteWasMissedEvent += OnNoteMiss; - } - else - { - _logger.Warn("scoreController or energyCounter or beatmapObjectManager is null!"); - } + _notesPassed = 0; + + _energyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0; + _energyCounter.gameEnergyDidReach0Event += OnEnergyDidReach0; + _scoreController.scoringForNoteFinishedEvent -= OnScoreChanged; + _scoreController.scoringForNoteFinishedEvent += OnScoreChanged; + _beatmapObjectManager.noteWasCutEvent -= OnNoteCut; + _beatmapObjectManager.noteWasCutEvent += OnNoteCut; + _beatmapObjectManager.noteWasMissedEvent -= OnNoteMiss; + _beatmapObjectManager.noteWasMissedEvent += OnNoteMiss; } private void OnNoteCut(NoteController noteController, in NoteCutInfo noteCutInfo) { - NotesPassed++; + _notesPassed++; } private void OnNoteMiss(NoteController noteController) { - NotesPassed++; + _notesPassed++; } private void OnEnergyDidReach0() { + if (EnergyDidReach0) return; + EnergyDidReach0 = true; - MaxRawScore = _scoreController?.immediateMaxPossibleMultipliedScore; - RawScore = _scoreController?.multipliedScore; - _logger.Info($"Energy reached 0! Notes fired: {NotesPassed} Scores w/o modifiers: {RawScore}/{MaxRawScore}"); + _maxRawScore = _scoreController.immediateMaxPossibleMultipliedScore; + _modifiedScore = _scoreController.modifiedScore; + _rawScore = _scoreController.multipliedScore; + _logger.Info($"Energy reached 0! Notes fired: {_notesPassed}, Scores: {_rawScore}/{_modifiedScore}/{_maxRawScore}"); + + FailScoreRecord = new ScoreRecord( + energyDidReach0:true, + rawScore:_rawScore, + modifiedScore:_modifiedScore, + maxRawScore:_maxRawScore, + notesPassed:_notesPassed); } private void OnScoreChanged(ScoringElement _) { - if (!EnergyDidReach0) - { - MaxRawScore = _scoreController?.immediateMaxPossibleMultipliedScore; - RawScore = _scoreController?.multipliedScore; - } + _maxRawScore = _scoreController.immediateMaxPossibleMultipliedScore; + _modifiedScore = _scoreController.modifiedScore; + _rawScore = _scoreController.multipliedScore; } public void Dispose() { - if (_energyCounter != null) - { - _energyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0; - } - - if (_scoreController != null) - { - _scoreController.scoringForNoteFinishedEvent -= OnScoreChanged; - } + _energyCounter.gameEnergyDidReach0Event -= OnEnergyDidReach0; + _scoreController.scoringForNoteFinishedEvent -= OnScoreChanged; + _beatmapObjectManager.noteWasCutEvent -= OnNoteCut; + _beatmapObjectManager.noteWasMissedEvent -= OnNoteMiss; + } + } + + public struct ScoreRecord + { + public readonly bool EnergyDidReach0; + public readonly int MaxRawScore; + public readonly int RawScore; + public readonly int ModifiedScore; + public readonly int NotesPassed; - if (_beatmapObjectManager != null) - { - _beatmapObjectManager.noteWasCutEvent -= OnNoteCut; - _beatmapObjectManager.noteWasMissedEvent -= OnNoteMiss; - } + internal ScoreRecord(bool energyDidReach0, int rawScore, int modifiedScore, int maxRawScore, int notesPassed) + { + EnergyDidReach0 = energyDidReach0; + RawScore = rawScore; + ModifiedScore = modifiedScore; + MaxRawScore = maxRawScore; + NotesPassed = notesPassed; + } + + public override string ToString() + { + return $"EnergyDidReach0 {EnergyDidReach0}, Notes fired: {NotesPassed}, Scores: {RawScore}/{ModifiedScore}/{MaxRawScore}"; } } } \ No newline at end of file