Skip to content

Commit

Permalink
Merge pull request #4 from qe201020335/master
Browse files Browse the repository at this point in the history
Update for Beat Saber 1.21.0
  • Loading branch information
Shadnix-was-taken authored Apr 10, 2022
2 parents e5dd4d6 + 08172b6 commit 498482d
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 56 deletions.
2 changes: 1 addition & 1 deletion SongPlayHistory.UnitTest/SongPlayHistory.UnitTest.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<IsPackable>false</IsPackable>
<BeatSaberDir>$(ProjectDir)..\SongPlayHistory\References</BeatSaberDir>
<BeatSaberDir>$(BeatSaberDir)</BeatSaberDir>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
Expand Down
28 changes: 14 additions & 14 deletions SongPlayHistory/BeatSaberUI.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using BS_Utils.Utilities;
using IPA.Utilities;
using HMUI;
using System.Linq;
using UnityEngine;
Expand Down Expand Up @@ -32,32 +32,32 @@ public static bool IsSolo
if (value)
{
_flowCoordinator = Resources.FindObjectsOfTypeAll<SoloFreePlayFlowCoordinator>().LastOrDefault();

ResultsViewController = _flowCoordinator?.GetPrivateField<ResultsViewController>("_resultsViewController");
var leaderboardViewController = _flowCoordinator?.GetPrivateField<PlatformLeaderboardViewController>("_platformLeaderboardViewController");
LeaderboardLevelStatsView = leaderboardViewController?.GetPrivateField<LevelStatsView>("_levelStatsView");
ResultsViewController = (_flowCoordinator as SoloFreePlayFlowCoordinator)?.GetField<ResultsViewController, SoloFreePlayFlowCoordinator>("_resultsViewController");
var leaderboardViewController = (_flowCoordinator as SoloFreePlayFlowCoordinator)?.GetField<PlatformLeaderboardViewController, SoloFreePlayFlowCoordinator>("_platformLeaderboardViewController");
LeaderboardLevelStatsView = leaderboardViewController?.GetField<LevelStatsView, PlatformLeaderboardViewController>("_levelStatsView");
}
else
{
var parent = Resources.FindObjectsOfTypeAll<GameServerLobbyFlowCoordinator>().LastOrDefault();
_flowCoordinator = parent?.GetPrivateField<MultiplayerLevelSelectionFlowCoordinator>("_multiplayerLevelSelectionFlowCoordinator");
_flowCoordinator = parent?.GetField<MultiplayerLevelSelectionFlowCoordinator, GameServerLobbyFlowCoordinator>("_multiplayerLevelSelectionFlowCoordinator");
}

var levelSelectionNavController = _flowCoordinator?.GetPrivateField<LevelSelectionNavigationController>("levelSelectionNavigationController");
var levelCollectionNavController = levelSelectionNavController?.GetPrivateField<LevelCollectionNavigationController>("_levelCollectionNavigationController");
LevelDetailViewController = levelCollectionNavController?.GetPrivateField<StandardLevelDetailViewController>("_levelDetailViewController");
var levelDetailView = LevelDetailViewController?.GetPrivateField<StandardLevelDetailView>("_standardLevelDetailView");
LevelParamsPanel = levelDetailView?.GetPrivateField<LevelParamsPanel>("_levelParamsPanel");
var levelCollectionViewController = levelCollectionNavController?.GetPrivateField<LevelCollectionViewController>("_levelCollectionViewController");
LevelCollectionTableView = levelCollectionViewController?.GetPrivateField<LevelCollectionTableView>("_levelCollectionTableView");
var levelSelectionNavController = _flowCoordinator?.GetField<LevelSelectionNavigationController, LevelSelectionFlowCoordinator>("levelSelectionNavigationController");
var levelCollectionNavController = levelSelectionNavController?.GetField<LevelCollectionNavigationController, LevelSelectionNavigationController>("_levelCollectionNavigationController");
LevelDetailViewController = levelCollectionNavController?.GetField<StandardLevelDetailViewController, LevelCollectionNavigationController>("_levelDetailViewController");
var levelDetailView = LevelDetailViewController?.GetField<StandardLevelDetailView, StandardLevelDetailViewController>("_standardLevelDetailView");
LevelParamsPanel = levelDetailView?.GetField<LevelParamsPanel, StandardLevelDetailView>("_levelParamsPanel");
var levelCollectionViewController = levelCollectionNavController?.GetField<LevelCollectionViewController, LevelCollectionNavigationController>("_levelCollectionViewController");
LevelCollectionTableView = levelCollectionViewController?.GetField<LevelCollectionTableView, LevelCollectionViewController>("_levelCollectionTableView");
}
}

public static void ReloadSongList()
{
if (IsValid)
{
LevelCollectionTableView?.GetPrivateField<TableView>("_tableView")?.RefreshCellsContent();
LevelCollectionTableView?.GetField<TableView, LevelCollectionTableView>("_tableView")?.RefreshCellsContent();
}
}
}
Expand Down
46 changes: 29 additions & 17 deletions SongPlayHistory/Plugin.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@
using BS_Utils.Gameplay;
using HarmonyLib;
using IPA;
using IPA.Config;
using IPA.Config.Stores;
using IPA.Logging;
using System;
using System.Collections.Generic;
using System.Reflection;
using BS_Utils.Utilities;
using Config = IPA.Config.Config;

namespace SongPlayHistoryContinued
{
Expand Down Expand Up @@ -38,12 +39,11 @@ public Plugin(Logger logger, Config config)
[OnStart]
public void OnStart()
{
BS_Utils.Utilities.BSEvents.gameSceneLoaded += OnGameSceneLoaded;
BS_Utils.Plugin.LevelDidFinishEvent += OnLevelFinished;
BS_Utils.Plugin.MultiLevelDidFinishEvent += OnMultilevelFinished;
BSEvents.gameSceneLoaded += OnGameSceneLoaded;
BSEvents.LevelFinished += OnLevelFinished;

// Init after the menu scene is loaded.
BS_Utils.Utilities.BSEvents.lateMenuSceneLoadedFresh += (o) =>
BSEvents.lateMenuSceneLoadedFresh += (o) =>
{
Log.Info("The menu scene was loaded.");
_ = new UnityEngine.GameObject(nameof(SPHController)).AddComponent<SPHController>();
Expand All @@ -55,9 +55,8 @@ public void OnStart()
[OnExit]
public void OnExit()
{
BS_Utils.Utilities.BSEvents.gameSceneLoaded -= OnGameSceneLoaded;
BS_Utils.Plugin.LevelDidFinishEvent -= OnLevelFinished;
BS_Utils.Plugin.MultiLevelDidFinishEvent -= OnMultilevelFinished;
BSEvents.gameSceneLoaded -= OnGameSceneLoaded;
BSEvents.LevelFinished -= OnLevelFinished;

SPHModel.BackupRecords();
}
Expand All @@ -68,23 +67,36 @@ private void OnGameSceneLoaded()
_isPractice = practiceSettings != null;
}

private void OnLevelFinished(StandardLevelScenesTransitionSetupDataSO scene, LevelCompletionResults result)
private void OnLevelFinished(object scene, LevelFinishedEventArgs eventArgs)
{
if (_isPractice || Gamemode.IsPartyActive)
if (eventArgs.LevelType != LevelType.Multiplayer && eventArgs.LevelType != LevelType.SoloParty)
{
return;
}
SaveRecord(scene?.difficultyBeatmap, result, false);
}

private void OnMultilevelFinished(MultiplayerLevelScenesTransitionSetupDataSO scene, LevelCompletionResults result, IReadOnlyList<MultiplayerPlayerResultsData> _)
{
SaveRecord(scene?.difficultyBeatmap, result, true);
var result = ((LevelFinishedWithResultsEventArgs)eventArgs).CompletionResults;

if (eventArgs.LevelType == LevelType.Multiplayer)
{
var beatmap = ((MultiplayerLevelScenesTransitionSetupDataSO)scene)?.difficultyBeatmap;
SaveRecord(beatmap, result, true);
}
else
{
// solo
if (_isPractice || Gamemode.IsPartyActive)
{
return;
}
var beatmap = ((StandardLevelScenesTransitionSetupDataSO)scene)?.difficultyBeatmap;
SaveRecord(beatmap, result, false);
}

}

private void SaveRecord(IDifficultyBeatmap beatmap, LevelCompletionResults result, bool isMultiplayer)
{
if (result?.rawScore > 0)
if (result?.multipliedScore > 0)
{
// Actually there's no way to know if any custom modifier was applied if the user failed a map.
var submissionDisabled = ScoreSubmission.WasDisabled || ScoreSubmission.Disabled || ScoreSubmission.ProlongedDisabled;
Expand All @@ -104,7 +116,7 @@ public void ApplyHarmonyPatches(bool enabled)
else if (!enabled && Harmony.HasAnyPatches(HarmonyId))
{
Log.Info("Removing Harmony patches...");
_harmony.UnpatchAll(HarmonyId);
_harmony.UnpatchSelf();

SetDataFromLevelAsync.OnUnpatch();
}
Expand Down
5 changes: 3 additions & 2 deletions SongPlayHistory/SPHController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,14 +139,15 @@ private void Refresh()
Plugin.Log?.Info("Refreshing data...");

var beatmap = BeatSaberUI.LevelDetailViewController?.selectedDifficultyBeatmap;
var playerData = SPHModel.GetPlayerData();
if (beatmap == null)
{
return;
}
try
{
_pluginUI.SetRecords(beatmap, SPHModel.GetRecords(beatmap));
_pluginUI.SetStats(beatmap, SPHModel.GetPlayerStats(beatmap));
_pluginUI.SetRecords(beatmap, playerData, SPHModel.GetRecords(beatmap));
_pluginUI.SetStats(beatmap, SPHModel.GetPlayerStats(beatmap), playerData);
}
catch (Exception ex) // Any UnityException
{
Expand Down
19 changes: 15 additions & 4 deletions SongPlayHistory/SPHModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using IPA.Utilities;

namespace SongPlayHistoryContinued
{
Expand Down Expand Up @@ -79,8 +80,8 @@ public static void SaveRecord(IDifficultyBeatmap beatmap, LevelCompletionResults
return;
}

// Cancelled?
if (result.levelEndStateType == LevelCompletionResults.LevelEndStateType.None)
// Cancelled.
if (result.levelEndStateType == LevelCompletionResults.LevelEndStateType.Incomplete)
{
return;
}
Expand Down Expand Up @@ -118,7 +119,7 @@ static Param ModsToParam(GameplayModifiers mods)
{
Date = DateTimeOffset.Now.ToUnixTimeMilliseconds(),
ModifiedScore = result.modifiedScore,
RawScore = result.rawScore,
RawScore = result.multipliedScore,
LastNote = cleared ? -1 : result.goodCutsCount + result.badCutsCount + result.missedCount,
Param = (int)param
};
Expand All @@ -144,7 +145,7 @@ public static PlayerLevelStatsData GetPlayerStats(IDifficultyBeatmap beatmap)
{
return null;
}
var playerDataModel = BeatSaberUI.LevelDetailViewController.GetPrivateField<PlayerDataModel>("_playerDataModel");
var playerDataModel = BeatSaberUI.LevelDetailViewController.GetField<PlayerDataModel, StandardLevelDetailViewController>("_playerDataModel");
var statsList = playerDataModel.playerData.levelsStatsData;
var stats = statsList?.FirstOrDefault(x => x.levelID == beatmap.level.levelID && x.difficulty == beatmap.difficulty);
if (stats == null)
Expand All @@ -153,6 +154,16 @@ public static PlayerLevelStatsData GetPlayerStats(IDifficultyBeatmap beatmap)
}
return stats;
}

public static PlayerData GetPlayerData()
{
if (!BeatSaberUI.IsValid)
{
return null;
}
var playerDataModel = BeatSaberUI.LevelDetailViewController.GetField<PlayerDataModel, StandardLevelDetailViewController>("_playerDataModel");
return playerDataModel.playerData;
}

public static bool ScanVoteData()
{
Expand Down
47 changes: 35 additions & 12 deletions SongPlayHistory/SPHUI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ private HoverHint HoverHint
hoverHint.text = "";
}
var hoverHintController = Resources.FindObjectsOfTypeAll<HoverHintController>().First();
hoverHint.SetPrivateField("_hoverHintController", hoverHintController);
hoverHint.SetField("_hoverHintController", hoverHintController);
return hoverHint;
}
}
Expand Down Expand Up @@ -125,9 +125,9 @@ private RectTransform PlayCount
}
}

public void SetRecords(IDifficultyBeatmap beatmap, List<Record> records)
public async void SetRecords(IDifficultyBeatmap beatmap, PlayerData playerData, List<Record> records)
{
if (HoverHint == null || beatmap == null)
if (HoverHint == null || beatmap == null || playerData == null)
{
return;
}
Expand All @@ -136,8 +136,9 @@ public void SetRecords(IDifficultyBeatmap beatmap, List<Record> records)
{
List<Record> truncated = records.Take(10).ToList();

var notesCount = beatmap.beatmapData.cuttableNotesCount;
var maxScore = ScoreModel.MaxRawScoreForNumberOfNotes(notesCount);
var beatmapData = await beatmap.GetBeatmapDataAsync(beatmap.GetEnvironmentInfo(), playerData.playerSpecificSettings);
var notesCount = beatmapData.cuttableNotesCount;
var maxScore = ScoreModel.ComputeMaxMultipliedScoreForBeatmap(beatmapData);
var builder = new StringBuilder(200);

static string ConcatParam(Param param)
Expand Down Expand Up @@ -183,9 +184,26 @@ static string Space(int len)
foreach (var r in truncated)
{
var localDateTime = DateTimeOffset.FromUnixTimeMilliseconds(r.Date).LocalDateTime;
var adjMaxScore = ScoreModel.MaxRawScoreForNumberOfNotes(r.LastNote);
var denom = PluginConfig.Instance.AverageAccuracy && r.LastNote > 0 ? adjMaxScore : maxScore;
var accuracy = r.RawScore / (float)denom * 100f;

/*
* To get a max possible score of an unfinished level, we need _transformedBeatmapData from ResultsViewController
* Then put it through ScoreModel.ComputeMaxMultipliedScoreForBeatmap
* So there is no way of recovering it from the data we stored in SongPlayData.json
*/

// var adjMaxScore = ScoreModel.MaxRawScoreForNumberOfNotes(r.LastNote);
// var denom = PluginConfig.Instance.AverageAccuracy && r.LastNote > 0 ? adjMaxScore : maxScore;
// var accuracy = r.RawScore / (float)denom * 100f;

var levelFinished = r.LastNote < 0;
var accuracy = r.RawScore / (float) maxScore * 100f;

/*
* One possible solution is to get the max possible score when a level finish as mentioned above,
* And store it in SongPlayData.json along all other things.
* Then we can just use this saved max score to calculate acc
*/

var param = ConcatParam((Param)r.Param);
if (param.Length == 0 && r.RawScore != r.ModifiedScore)
{
Expand All @@ -196,7 +214,12 @@ static string Space(int len)
builder.Append(Space(truncated.Count - truncated.IndexOf(r) - 1));
builder.Append($"<size=2.5><color=#1a252bff>{localDateTime:d}</color></size>");
builder.Append($"<size=3.5><color=#0f4c75ff> {r.ModifiedScore}</color></size>");
builder.Append($"<size=3.5><color=#368cc6ff> {accuracy:0.00}%</color></size>");
if (levelFinished)
{
// only display acc if the record is a finished level
builder.Append($"<size=3.5><color=#368cc6ff> {accuracy:0.00}%</color></size>");

}
if (param.Length > 0)
{
builder.Append($"<size=2><color=#1a252bff> {param}</color></size>");
Expand All @@ -222,7 +245,7 @@ static string Space(int len)
}
}

public void SetStats(IDifficultyBeatmap beatmap, PlayerLevelStatsData stats)
public async void SetStats(IDifficultyBeatmap beatmap, PlayerLevelStatsData stats, PlayerData playerData)
{
if (beatmap == null || stats == null)
{
Expand All @@ -244,8 +267,8 @@ static void SetValue(RectTransform column, string value)
var maxCombo = LevelStatsView.GetComponentsInChildren<RectTransform>().First(x => x.name == "MaxCombo");
var highscore = LevelStatsView.GetComponentsInChildren<RectTransform>().First(x => x.name == "Highscore");
var maxRank = LevelStatsView.GetComponentsInChildren<RectTransform>().First(x => x.name == "MaxRank");
var notesCount = beatmap.beatmapData.cuttableNotesCount;
var maxScore = ScoreModel.MaxRawScoreForNumberOfNotes(notesCount);
var beatmapData = await beatmap.GetBeatmapDataAsync(beatmap.GetEnvironmentInfo(), playerData.playerSpecificSettings);
var maxScore = ScoreModel.ComputeMaxMultipliedScoreForBeatmap(beatmapData);
var estimatedAcc = stats.highScore / (float)maxScore * 100f;
SetValue(maxCombo, stats.validScore ? $"{stats.maxCombo}" : "-");
SetValue(highscore, stats.validScore ? $"{stats.highScore} ({estimatedAcc:0.00}%)" : "-");
Expand Down
3 changes: 2 additions & 1 deletion SongPlayHistory/SongPlayHistoryContinued.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,8 +130,9 @@
<ErrorOnMismatchedVersions Condition="'$(Configuration)' == 'Release'">True</ErrorOnMismatchedVersions>
</PropertyGroup>
<Target Name="CopyToPlugins" AfterTargets="Build" Condition="'$(NCrunch)' != '1'">
<Message Text="Copying $(OutputAssemblyName).dll to IPA\Pending\Plugins folder" Importance="high" />
<Message Text="Copying $(OutputAssemblyName).dll and $(OutputAssemblyName).pdb to IPA\Pending\Plugins folder" Importance="high" />
<Copy SourceFiles="$(OutputAssemblyName).dll" DestinationFiles="$(BeatSaberDir)\IPA\Pending\Plugins\$(AssemblyName).dll" />
<Copy SourceFiles="$(OutputAssemblyName).pdb" DestinationFiles="$(BeatSaberDir)\IPA\Pending\Plugins\$(AssemblyName).pdb" />
</Target>
<Target Name="GetProjectInfo" AfterTargets="BeforeBuild" Condition="'$(BSMTTaskAssembly)' != ''">
<GetManifestInfo ManifestPath="manifest.json">
Expand Down
10 changes: 5 additions & 5 deletions SongPlayHistory/manifest.json
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
{
"author": "peperoro",
"description": "A score tracker with simple in-game UI.",
"gameVersion": "1.17.0",
"gameVersion": "1.21.0",
"id": "SongPlayHistoryContinued",
"name": "SongPlayHistoryContinued",
"version": "1.6.1",
"version": "1.6.2",
"dependsOn": {
"BSIPA": "^4.1.6",
"BeatSaberMarkupLanguage": "^1.5.3",
"BS Utils": "^1.10.0"
"BSIPA": "^4.2.2",
"BeatSaberMarkupLanguage": "^1.6.3",
"BS Utils": "^1.12.0"
},
"links": {
"project-home": "https://github.com/Shadnix-was-taken/BeatSaber-SongPlayHistoryContinued"
Expand Down

0 comments on commit 498482d

Please sign in to comment.